juc之volatile關鍵字及cas算法

1.共享變量可見性問題

  • java內存模型

image.png

  • 當一個線程操做了共享變量以後,僅僅會寫入該線程緩存中,並不會及時寫入主存中,那麼別的線程此時從主存中獲取到共享變量,就會致使異常。
  • volatile關鍵字:若是一個變量聲明爲volatile後,每一個線程操做共享變量後就會當即同步到主存中,此功能是底層硬件支持的。也就是說volatile關鍵字解決了共享變量的可見性問題,但沒有解決變量的原子性以及互斥性。 原子類中的變量所有聲明爲volatile,保證線程可見性,原子類使用cas算法保證原子性。java

    public class VolatileDemo {
       public static void main(String[] args) {
    
           ThreadClass threadClass = new ThreadClass();
           Thread thread = new Thread(threadClass);
           thread.start();
    
           while (true){
               if (threadClass.shareVar){//在這裏main線程訪問共享變量,該共享變量是main線程的變量副本
                   System.out.println("ShareVariableClass.shareVar:" + threadClass.shareVar);
                   break;
               }
           }
       }
    }
    
    class ThreadClass implements Runnable{
    
       public volatile boolean shareVar = false;
    
       @Override
       public void run() {
           try {
               Thread.sleep(200);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           this.shareVar = true;
           System.out.println("sharVar change to " + shareVar);
       }
    }

        結果以下,結果中打印的順序會不一致。
    image.png算法

2.CAS算法

    CAS:全稱compare and swap,比較並交換。當多個線程操做共享變量的時候,每一個線程的操做都寫入主存中,就會致使主存中的共享變量不可以保證原子性。若是要操做一個變量s進行+1操做,在+操做以前,獲取主存中s的值(經過volatile關鍵字保證可見性)做爲指望值expectValue,將s進行+1操做後,寫入主存以前經過將目前的主存值和expectValue值作比較,若是相同則將s+1的值寫入主存,若是不相等,則重複進行上述步驟。緩存

    以AtomicInteger舉例ide

AtomicInteger atomicInteger = new AtomicInteger(10);
int andIncrement = atomicInteger.getAndIncrement();

    cas操做最終調用的方法是Unsafe類中的native方法調用,除了Integer類型的原子操做,還有Boolean等的類型操做,但調用是以下三個方法來保證原子性。boolean類型是經過轉換爲int類型來進行操做的。
    
image.png
    
image.pngthis

    全部原子類以下
image.pngatom

相關文章
相關標籤/搜索