成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java多線程進階(十三)—— J.U.C之a(chǎn)tomic框架:AtomicInteger

darkbug / 1551人閱讀

摘要:顧名思義,是類型的線程安全原子類,可以在應(yīng)用程序中以原子的方式更新值。創(chuàng)建對象先來看下對象的創(chuàng)建。也就是說當(dāng)一個線程修改一個共享變量時,其它線程能立即讀到這個修改的值。

本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog...
一、AtomicInteger簡介

AtomicInteger,應(yīng)該是atomic框架中用得最多的原子類了。顧名思義,AtomicInteger是Integer類型的線程安全原子類,可以在應(yīng)用程序中以原子的方式更新int值。

1. 創(chuàng)建AtomicInteger對象

先來看下AtomicInteger對象的創(chuàng)建。

AtomicInteger提供了兩個構(gòu)造器,使用默認構(gòu)造器時,內(nèi)部int類型的value值為0:
AtomicInteger atomicInt = new AtomicInteger();

AtomicInteger類的內(nèi)部并不復(fù)雜,所有的操作都針對內(nèi)部的int值——value,并通過Unsafe類來實現(xiàn)線程安全的CAS操作:

2. AtomicInteger的使用

來看下面這個示例程序:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger ai = new AtomicInteger();

        List list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(new Accumlator(ai), "thread-" + i);
            list.add(t);
            t.start();
        }

        for (Thread t : list) {
            t.join();
        }

        System.out.println(ai.get());
    }

    static class Accumlator implements Runnable {
        private AtomicInteger ai;

        Accumlator(AtomicInteger ai) {
            this.ai = ai;
        }

        @Override
        public void run() {
            for (int i = 0, len = 1000; i < len; i++) {
                ai.incrementAndGet();
            }
        }
    }
}

上述代碼使用了AtomicInteger的incrementAndGet方法,以原子的操作對int值進行自增,該段程序執(zhí)行的最終結(jié)果為10000(10個線程,每個線程對AtomicInteger增加1000),如果不使用AtomicInteger,使用原始的int或Integer,最終結(jié)果值可能會小于10000(并發(fā)時讀到了過時的數(shù)據(jù)或存在值覆蓋的問題)。

我們來看下incrementAndGet內(nèi)部:

內(nèi)部調(diào)用了Unsafe類的getAndAddInt方法,以原子方式將value值增加1,然后返回增加前的原始值。

注意,上述是JDK1.8的實現(xiàn),在JDK1.8之前,上述方法采用了自旋+CAS操作的方式:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}
3. AtomicInteger的特殊方法說明

AtomicInteger中有一個比較特殊的方法——lazySet

lazySet方法是set方法的不可見版本。什么意思呢?

我們知道通過volatile修飾的變量,可以保證在多處理器環(huán)境下的“可見性”。也就是說當(dāng)一個線程修改一個共享變量時,其它線程能立即讀到這個修改的值。volatile的實現(xiàn)最終是加了內(nèi)存屏障:

保證寫volatile變量會強制把CPU寫緩存區(qū)的數(shù)據(jù)刷新到內(nèi)存

讀volatile變量時,使緩存失效,強制從內(nèi)存中讀取最新的值

由于內(nèi)存屏障的存在,volatile變量還能阻止重排序

lazySet內(nèi)部調(diào)用了Unsafe類的putOrderedInt方法,通過該方法對共享變量值的改變,不一定能被其他線程立即看到。也就是說以普通變量的操作方式來寫變量。

為什么會有這種奇怪方法?什么情況下需要使用lazySet呢?

考慮下面這樣一個場景:

private AtomicInteger ai = new AtomicInteger();
lock.lock();
try
{
    // ai.set(1);
}
finally
{
    lock.unlock();
}

由于鎖的存在:

lock()方法獲取鎖時,和volatile變量的讀操作一樣,會強制使CPU緩存失效,強制從內(nèi)存讀取變量。

unlock()方法釋放鎖時,和volatile變量的寫操作一樣,會強制刷新CPU寫緩沖區(qū),把緩存數(shù)據(jù)寫到主內(nèi)存

所以,上述ai.set(1)可以用ai.lazySet(1)方法替換:

由鎖來保證共享變量的可見性,以設(shè)置普通變量的方式來修改共享變量,減少不必要的內(nèi)存屏障,從而提高程序執(zhí)行的效率。

二、類/接口說明 類聲明

構(gòu)造器

接口聲明
方法聲明 描述
int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) 使用IntBinaryOperator 對當(dāng)前值和x進行計算,并更新當(dāng)前值,返回計算后的新值
int addAndGet(int delta) 以原子方式將給定值與當(dāng)前值相加,返回相加后的新值
boolean compareAndSet(int expect, int update) 如果當(dāng)前值 == expect,則以原子方式將該值設(shè)置為給定的更新值(update)
int decrementAndGet() 以原子方式將當(dāng)前值減 1,返回新值
int get() 獲取當(dāng)前值
int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) 使用IntBinaryOperator 對當(dāng)前值和x進行計算,并更新當(dāng)前值,返回計算前的舊值
int getAndAdd(int delta) 以原子方式將給定值與當(dāng)前值相加,返回舊值
int getAndDecrement() 以原子方式將當(dāng)前值減 1,返回舊值
int getAndIncrement() 以原子方式將當(dāng)前值加 1,返回舊值
int getAndSet(int newValue) 以原子方式設(shè)置為給定值,并返回舊值
int getAndUpdate(IntUnaryOperator updateFunction) 使用IntBinaryOperator 對當(dāng)前值進行計算,并更新當(dāng)前值,返回計算前的舊值
int incrementAndGet() 以原子方式將當(dāng)前值加 1,返回新值
void lazySet(int newValue) 設(shè)置為給定值,但不保證值的改變被其他線程立即看到
void set(int newValue) 設(shè)置為給定值
int updateAndGet(IntUnaryOperator updateFunction) 使用IntBinaryOperator 對當(dāng)前值進行計算,并更新當(dāng)前值,返回計算后的新值
boolean weakCompareAndSet(int expect, int update) weakCompareAndSet無法保證除操作目標(biāo)外的其他變量的執(zhí)行順序( 編譯器和處理器為了優(yōu)化程序性能而對指令序列進行重新排序 ),同時也無法保證這些變量的可見性。
三、其它原子類

AtomicInteger類似的原子類還有AtomicBooleanAtomicLong,底層都是通過Unsafe類做CAS操作,來原子的更新狀態(tài)值。可以參考Oracle官方文檔:https://docs.oracle.com/javas...,不再贅述。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76561.html

相關(guān)文章

  • Java線程進階(一)—— J.U.C并發(fā)包概述

    摘要:整個包,按照功能可以大致劃分如下鎖框架原子類框架同步器框架集合框架執(zhí)行器框架本系列將按上述順序分析,分析所基于的源碼為。后,根據(jù)一系列常見的多線程設(shè)計模式,設(shè)計了并發(fā)包,其中包下提供了一系列基礎(chǔ)的鎖工具,用以對等進行補充增強。 showImg(https://segmentfault.com/img/remote/1460000016012623); 本文首發(fā)于一世流云專欄:https...

    anonymoussf 評論0 收藏0
  • Java線程進階(十五)—— J.U.Catomic框架Atomic數(shù)組

    摘要:注意原子數(shù)組并不是說可以讓線程以原子方式一次性地操作數(shù)組中所有元素的數(shù)組。類的方法返回指定類型數(shù)組的元素所占用的字節(jié)數(shù)。,是將轉(zhuǎn)換為進制,然后從左往右數(shù)連續(xù)的個數(shù)。 showImg(https://segmentfault.com/img/remote/1460000016012145); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... 一...

    lunaticf 評論0 收藏0
  • Java線程進階(十六)—— J.U.Catomic框架:FieldUpdater

    摘要:所謂,就是可以以一種線程安全的方式操作非線程安全對象的某些字段。我們來對上述代碼進行改造賬戶類改造引入通過操作字段調(diào)用方,并未做任何改變上述代碼,無論執(zhí)行多少次,最終結(jié)果都是,因為這回是線程安全的。這也是整個包的設(shè)計理念之一。 showImg(https://segmentfault.com/img/remote/1460000016012109); 本文首發(fā)于一世流云的專欄:http...

    darcrand 評論0 收藏0
  • Java線程進階(十二)—— J.U.Catomic框架:Unsafe類

    摘要:本身不直接支持指針的操作,所以這也是該類命名為的原因之一。中的許多方法,內(nèi)部其實都是類在操作。 showImg(https://segmentfault.com/img/remote/1460000016012251); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... 一、Unsafe簡介 在正式的開講 juc-atomic框架系列之前,有...

    趙連江 評論0 收藏0
  • Java線程進階(十四)—— J.U.Catomic框架AtomicReference

    摘要:但是,有些操作會依賴于對象的變化過程,此時的解決思路一般就是使用版本號。在變量前面追加上版本號,每次變量更新的時候把版本號加一,那么就會變成。四的引入就是上面所說的加了版本號的。 showImg(https://segmentfault.com/img/remote/1460000016012188); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blo...

    aboutU 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<