AtomicInteger的使用


AtomicInteger的使用

  在之前一篇volatile學習里面提到過了,volatile修飾的變量只是保證內存可見性,無法保證原子性,可能出現寫沖突。要想保證線程安全,需要使用AtomicInteger。具體代碼如下:

public class AtomicTest {
    public static AtomicInteger race=new AtomicInteger(0);
    public static void increase(){
        race.incrementAndGet();
    }
    private static final int THREADS_COUNT=20;
    public static void main(String[] args){
        Thread[] threads=new Thread[THREADS_COUNT];
        for(int i=0;i<THREADS_COUNT;i++){
            threads[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<10000;i++){
                        increase();
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount()>1){
            Thread.yield();
            System.out.println(race);
        }
    }
}

 

運行結果為200000,若是把變量用volatile修飾,然后increase方法替換成race++,那么最后得到的結果基本不為200000,且每一次得到的結果都可能是不同的。AtomicInteger的incrementAndGet是通過unsafe的getAndAddInt來實現的,而后者的代碼如下:

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

 

  其中var1是調用unsafe的AtomicInteger對象,而var2是用來記錄value本身在內存的編譯地址的,這個記錄,也主要是為了在更新操作在內存中找到value的位置,方便比較。而var5則是AtomicInteger的value值,被valotile修飾,當沖突時因為內存可見性,操作失敗的線程可以看到修改成功的線程修改后的最新值。compareAndSwapInt亦即CAS,是原子操作,它的作用是若原值為var5即在這之間沒發生過修改,那么設置為新值var5 + var4。AtomicInteger方法不是互斥同步的,而是非阻塞同步,也就是樂觀鎖,而前者被稱為悲觀鎖。

  悲觀鎖認為沖突經常會發生,所以直接上鎖,強制所有線程一次有且只有一條線程能操作,嚴格保證串行性。而樂觀鎖認為沖突很少發生,先進行操作,之后檢查有沒有沖突,若發生了沖突再采取其他補償措施(最常見的補償措施就是不斷地重試,直到成功為止)。兩者並無優劣之分,使用場景不同而已。若是沖突經常發生,那么采用樂觀鎖場景中,每次操作只有一條線程成功,失敗的線程會不斷嘗試然后不斷沖突,性能可能很差,但若是沖突很少發生,那么悲觀鎖那樣一次只允許一條線程讀寫那么效率就太低了。樂觀鎖是通過檢查版本號來檢測是否發生沖突的,而版本號每次修改成功時+1。你每次需要修改值時帶上版本號,若是你的版本號與當前一致那么修改成功,若是中間被其他線程修改了,那么版本號就與你的不一樣了,你只能請求最新的版本號然后嘗試着再次修改直到成功為止。像版本號這樣單向增加的比較好,若是用原值來作為比較的標准的話,有可能會發生中間有人把原值加1另外一人把原值減1,然后輪到你的時候你以為原值在這中間沒有變化而可能產生歧義,亦即ABA問題。而版本號只要發生了修改都會增加而無論操作是什么。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM