Java AtomicInteger的用法

1具壮、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray,
AtomicReference等原子類的類,主要用于在高并發(fā)環(huán)境下的高效程序處理,來幫助我們簡化同步處理.

在Java語言中,++i和i++操作并不是線程安全的弦赖,在使用的時(shí)候,不可避免的會(huì)用到synchronized關(guān)鍵字浦辨。而AtomicInteger則通過一種線程安全的加減操作接口蹬竖。

2、AtomicInteger的基本方法

  • 創(chuàng)建一個(gè)AtomicInteger
  System.out.println(atomicInteger.get());


--->輸出 : 123
  • 創(chuàng)建一個(gè)不傳值的流酬,默認(rèn)值為0
  AtomicInteger atomicInteger = new AtomicInteger();
  System.out.println(atomicInteger.get());
---->輸出: 0
  • 獲取和賦值
atomicInteger.get(); //獲取當(dāng)前值
atomicInteger.set(999); //設(shè)置當(dāng)前值

atomicInteger.compareAndSet(expectedValue,newValue)

 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        System.out.println(atomicInteger.get());

        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);

    }

----》輸出結(jié)果為: 0 false 0


 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());

        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);

    }

-----》輸出結(jié)果為: 123 true  234

由上可知該方法表示币厕,atomicInteger的值與expectedValue相比較,如果不相等芽腾,則返回false,
atomicInteger原有值保持不變旦装;如果兩者相等,則返回true,atomicInteger的值更新為newValue

  • getAndAdd()方法與AddAndGet方法
       AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());  --123

        System.out.println(atomicInteger.getAndAdd(10)); --123 獲取當(dāng)前值摊滔,并加10
        System.out.println(atomicInteger.get()); --133


        System.out.println(atomicInteger.addAndGet(10)); --143 獲取加10后的值阴绢,先加10
        System.out.println(atomicInteger.get()); --143
  • getAndDecrement()和DecrementAndGet()方法
        AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());   --123

        System.out.println(atomicInteger.getAndDecrement()); --123 獲取當(dāng)前值并自減
        System.out.println(atomicInteger.get());  --122


        System.out.println(atomicInteger.decrementAndGet()); --121 先自減再獲取減1后的值
        System.out.println(atomicInteger.get()); --121

3、使用AtomicInteger艰躺,即使不用同步塊synchronized呻袭,最后的結(jié)果也是100,可用看出AtomicInteger的作用腺兴,用原子方式更新的int值左电。主要用于在高并發(fā)環(huán)境下的高效程序處理。使用非阻塞算法來實(shí)現(xiàn)并發(fā)控制。

public class Counter {

    public static AtomicInteger count = new AtomicInteger(0);

    public static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常篓足,防止程序中斷
            e.printStackTrace();

        }
        count.getAndIncrement();//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運(yùn)行結(jié)果:"+Counter.count);


    }
}

運(yùn)行結(jié)果: 100

4段誊、使用普通Integer

public class Counter {

    public volatile  static int count = 0;

    public static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常,防止程序中斷
            e.printStackTrace();

        }
        count++;//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運(yùn)行結(jié)果:"+Counter.count);
   }
}
運(yùn)行結(jié)果:98

5纷纫、如果在inc方法前面加個(gè)synchronized也能是線程安全的枕扫;

它用來修飾一個(gè)方法或者一個(gè)代碼塊的時(shí)候,能夠保證在同一時(shí)刻最多只有一個(gè)線程執(zhí)行該段代碼辱魁。

import java.util.concurrent.CountDownLatch;

/**
 * created by guanguan  on 2017/10/23
 **/
public class Counter {

     public volatile static  Integer count = 0;

    public synchronized static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常烟瞧,防止程序中斷
            e.printStackTrace();

        }
          count++;//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運(yùn)行結(jié)果:"+Counter.count);


    }
}

運(yùn)行結(jié)果:100

synchronized的使用說明:

一、當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對象object中的這個(gè)synchronized(this)同步代碼塊時(shí)染簇,一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行参滴。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。

二锻弓、然而砾赔,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問該object中的非synchronized(this)同步代碼塊青灼。

三暴心、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí)杂拨,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞专普。

四、第三個(gè)例子同樣適用其它同步代碼塊弹沽。也就是說檀夹,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對象鎖策橘。結(jié)果炸渡,其它線程對該object對象所有同步代碼部分的訪問都被暫時(shí)阻塞。

五丽已、以上規(guī)則對其它對象鎖同樣適用.

6蚌堵、從上面的例子中我們可以看出:使用AtomicInteger是非常的安全的.而且因?yàn)锳tomicInteger由硬件提供原子操作指令實(shí)現(xiàn)的。在非激烈競爭的情況下沛婴,開銷更小吼畏,速度更快。

java的關(guān)鍵域有3個(gè)

// setup to use Unsafe.compareAndSwapInt for updates  
private static final Unsafe unsafe = Unsafe.getUnsafe();  
private static final long valueOffset;  
private volatile int value; 

這里瘸味, unsafe是java提供的獲得對對象內(nèi)存地址訪問的類宫仗,注釋已經(jīng)清楚的寫出了,它的作用就是在更新操作時(shí)提供“比較并替換”的作用旁仿。實(shí)際上就是AtomicInteger中的一個(gè)工具藕夫。

valueOffset是用來記錄value本身在內(nèi)存的便宜地址的孽糖,這個(gè)記錄,也主要是為了在更新操作在內(nèi)存中找到value的位置毅贮,方便比較办悟。

注意:value是用來存儲(chǔ)整數(shù)的時(shí)間變量,這里被聲明為volatile滩褥,就是為了保證在更新操作時(shí)病蛉,當(dāng)前線程可以拿到value最新的值(并發(fā)環(huán)境下,value可能已經(jīng)被其他線程更新了)瑰煎。

這里铺然,我們以自增的代碼為例,可以看到這個(gè)并發(fā)控制的核心算法:

源碼

 public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酒甸,一起剝皮案震驚了整個(gè)濱河市魄健,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌插勤,老刑警劉巖沽瘦,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異农尖,居然都是意外死亡析恋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門盛卡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來助隧,“玉大人,你說我怎么就攤上這事窟扑±洌” “怎么了漏健?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵嚎货,是天一觀的道長。 經(jīng)常有香客問我蔫浆,道長殖属,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任瓦盛,我火速辦了婚禮洗显,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘原环。我一直安慰自己挠唆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布嘱吗。 她就那樣靜靜地躺著玄组,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俄讹,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天哆致,我揣著相機(jī)與錄音,去河邊找鬼患膛。 笑死摊阀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的踪蹬。 我是一名探鬼主播胞此,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼跃捣!你這毒婦竟也來了豌鹤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枝缔,失蹤者是張志新(化名)和其女友劉穎布疙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愿卸,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灵临,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趴荸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儒溉。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖发钝,靈堂內(nèi)的尸體忽然破棺而出顿涣,到底是詐尸還是另有隱情,我是刑警寧澤酝豪,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布涛碑,位于F島的核電站,受9級特大地震影響孵淘,放射性物質(zhì)發(fā)生泄漏蒲障。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一瘫证、第九天 我趴在偏房一處隱蔽的房頂上張望揉阎。 院中可真熱鬧,春花似錦背捌、人聲如沸毙籽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坑赡。三九已至巡扇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垮衷,已是汗流浹背厅翔。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搀突,地道東北人刀闷。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像仰迁,于是被迫代替她去往敵國和親甸昏。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容