Java多線程---CAS和鎖優化

    一 .CAS

       在學習java.util.concurrent(簡稱JUC)包下的類時,瞭解到了CAS這個概念,整個JUC包的基礎也是CAS,ReentrantLock也是基於它的。學習CAS,先從synchronized關鍵字說起,synchronized關鍵字能保證最基本的互斥同步。同步是指在多個線程併發訪問共享數據時,保證共享數據在同一個時刻只被一個線程使用。而互斥是實現同步的一種手段。互斥同步4個字,互斥是因,同步是果;互斥是方法,同步是目的。互斥同步屬於一種悲觀的併發政策,認爲如果不進行正確的同步措施,那就好出現問題,無論共享數據是否真會出現競爭,它都要進行加鎖。

    隨着硬件指令集的發展,多了一個選擇:基於衝突檢測的樂觀併發政策,先進性操作,如果沒有其他線程共享數據,則操作成功;如果共享數據有爭用,產生衝突,那就採取其他措施(不斷重試),這種樂觀的併發政策的許多實現不用把線程掛起。樂觀併發政策需要操作和衝突檢測兩個步驟具有原子性,需要底層硬件完成。

   x86中通過cmpxchg彙編指令來完成CAS操作。CAS(Compare-and-Swap 比較和交換)與平臺相關,它有三個操作數,內存位置值(V),舊的預期值(A),新值(B)。CAS指令執行時,當V=A時,處理器用B的值跟新V的值,否則不執行。上述的過程是一個原子操作。JDK1.5引入的CAS,它在sun.misc.Unsafe類裏面方法提供。裏面調用了Native方法。

下面給一個JUC包下面的Atomic類的部分源代碼,執行自增操作。用到CAS,裏面用到了循環一直判斷。裏面沒有進行加鎖處理。但是也有邏輯漏洞,在111和222如果其他線程被執行,獲得V(V運來是A),將他修改爲B,後來又修改會A,則執行222代碼的時候認爲V沒有改變過,這就是“ABA”問題。這個問題一般沒有什麼影響。

//該方法實現了i++的非阻塞的原子操作 
   public final int getAndIncrement() { 
         for (;;) { //循環,使用CAS的經典方式,這是實現non-blocking方式的代價 
            int current = get();//得到現在的值     111
            int next = current + 1;//通過計算得到要賦予的新值 
            if (compareAndSet(current, next)) //關鍵點,調用CAS原子更新,  222
                 return current; 
         } 
     } 

    二.鎖優化

   JDK1.6中高校併發是一個重要改進。裏面的給出的各種鎖都是爲了線程間更高效的共享數據。優化的方法有下面幾種。這裏的鎖優化主要是針對synchronized關鍵字來說,它產生的是一種重量級的鎖定(重量級的鎖定不是用CAS),會有互斥,效率較低。而在JDK1.6後,引入的自旋鎖,輕量級鎖,偏向鎖對互斥同步進行了優化,它們三種鎖默認都是開啓的。

1.鎖消除,鎖粗化。鎖消除是判斷當堆上的數據不會被其他線程訪問到時,該線程上的同步加鎖就無需進行。

由於加鎖和解鎖的開銷很大,如果不斷的加鎖和解鎖操作都是對於同一個對象,虛擬機會把整個加鎖同步的範圍擴張到操作序列的外部,就是隻加一次鎖。

2.自旋鎖:互斥同步對性能最大的影響是阻塞的實現,掛起線程和恢復線程都需要轉入內核中完成。現將本該要阻塞的線程不去掛起,不放棄處理器的執行時間,而是在那做一個忙循環(自旋),看看持有鎖的線程是否很快釋放鎖。自旋的次數(循環的次數)是有限度的,默認是10次,如果沒有獲得鎖就採用傳統的方式去掛起線程。

3.輕量級鎖:在線程沒有競爭的時候,採用CAS操作,避免使用互斥量的開銷。這裏涉及到對象頭的概念。

4.偏向鎖:它相對於輕量級鎖,減少了鎖重入的開銷,對於第一個獲得鎖的線程,後面的執行如果該鎖沒有被其他線程獲取,則該線程將不再進行同步(CAS操作)。

      輕量級鎖和偏向鎖都是在沒有競爭的情況下出現,一旦出現競爭就會升級爲重量級鎖。

對於synchronized,鎖的升級情況可能是 偏向鎖—>輕量鎖—>自適應自旋鎖—>重量鎖

 參考:

        《深入理解Java虛擬機》

         http://www.majin163.com/2014/03/17/synchronized2/  這一篇博文寫了synchronized的原理,它的實現和性能怎麼樣可以看看這一篇。



發佈了26 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章