1. 程式人生 > >JDK 原子操作類詳解(AtomicInteger、AtomicIntegerArray等)

JDK 原子操作類詳解(AtomicInteger、AtomicIntegerArray等)

當程式更新一個變數時,如果多執行緒同時更新這個變數,可能得到期望之外的值,比如變數i=1,A執行緒更新i+1,B執行緒也更新i+1,經過兩個執行緒操作之後可能i不等於3,而是等於2。因為A和B執行緒在更新變數i的時候拿到的i都是1,這就是執行緒不安全的更新操作,通常我們會使用synchronized來解決這個問題,synchronized會保證多執行緒不會同時更新變數i。

  1. import java.util.concurrent.CountDownLatch;  
  2. publicclass UnSafeAdd {  
  3.     privatestaticint threadCount=10;  
  4.     private
    static CountDownLatch countDown=new CountDownLatch(threadCount);  
  5.     privatestaticint count=0;  
  6.     privatestaticclass Counter implements Runnable{   
  7.         @Override
  8.         publicvoid run() {  
  9.             for(int i=0;i<1000;i++){  
  10.                 count++;//非原子操作
  11.             }   
  12.             countDown.countDown();  
  13.         }   
  14.     }  
  15.     publicstaticvoid main(String[] args) throws InterruptedException {  
  16.         Thread[] threads=new Thread[threadCount];  
  17.         for(int i=0;i<threadCount;i++){  
  18.             threads[i]=new Thread(new Counter());  
  19.         }  
  20.         for(int i=0;i<threadCount;i++){  
  21.             threads[i].start();;  
  22.         }  
  23.         countDown.await();  
  24.         System.out.println(count);  
  25.     }  
輸出:

8968

  1. import java.util.concurrent.CountDownLatch;  
  2. publicclass SafeAddWithSyn {  
  3.     privatestaticint threadCount=10;  
  4.     privatestatic CountDownLatch countDown=new CountDownLatch(threadCount);  
  5.     privatestaticint count=0;  
  6.     synchronizedprivatestaticvoid addCount(){//同步方法
  7.         count++;  
  8.     }  
  9.     privatestaticclass Counter implements Runnable{   
  10.         @Override
  11.         publicvoid run() {  
  12.             for(int i=0;i<1000;i++){  
  13.                 addCount();  
  14.             }   
  15.             countDown.countDown();  
  16.         }   
  17.     }  
  18.     publicstaticvoid main(String[] args) throws InterruptedException {  
  19.         Thread[] threads=new Thread[threadCount];  
  20.         for(int i=0;i<threadCount;i++){  
  21.             threads[i]=new Thread(new Counter());  
  22.         }  
  23.         for(int i=0;i<threadCount;i++){  
  24.             threads[i].start();;  
  25.         }  
  26.         countDown.await();  
  27.         System.out.println(count);  
  28.     }  
  29. }  
輸出:

10000

而Java從JDK 1.5開始提供了java.util.concurrent.atomic包(以下簡稱Atomic包),這個包中的原子操作類提供了一種用法簡單、效能高效、執行緒安全地更新一個變數的方式。因為變數的型別有很多種,所以在Atomic包裡一共提供了13個類,屬於4種類型的原子更新方式,分別是原子更新基本型別、原子更新陣列、原子更新引用和原子更新屬性(欄位)。Atomic包裡的類基本都是使用Unsafe實現的包裝類。

  1. import java.util.concurrent.CountDownLatch;  
  2. import java.util.concurrent.atomic.AtomicInteger;  
  3. publicclass SafeAddWithAtomicInteger {  
  4.     privatestaticint threadCount=10;  
  5.     privatestatic CountDownLatch countDown=new CountDownLatch(threadCount);  
  6.     privatestatic AtomicInteger count=new AtomicInteger(0);//原子操作類
  7.     privatestaticclass Counter implements Runnable{   
  8.         @Override
  9.         publicvoid run() {  
  10.             for(int i=0;i<1000;i++){  
  11.                 count.addAndGet(1);  
  12.             }   
  13.             countDown.countDown();  
  14.         }   
  15.     }  
  16.     publicstaticvoid main(String[] args) throws InterruptedException {  
  17.         Thread[] threads=new Thread[threadCount];  
  18.         for(int i=0;i<threadCount;i++){  
  19.             threads[i]=new Thread(new Counter());  
  20.         }  
  21.         for(int i=0;i<threadCount;i++){  
  22.             threads[i].start();;  
  23.         }  
  24.         countDown.await();  
  25.         System.out.println(count.get());  
  26.     }  
  27. }  
輸出:

10000

原子更新基本型別

使用原子的方式更新基本型別,Atomic包提供了以下3個類。
AtomicBoolean:原子更新布林型別。
AtomicInteger:原子更新整型。
AtomicLong:原子更新長整型。
以上3個類提供的方法幾乎一模一樣,所以本節僅以AtomicInteger為例進行講解,AtomicInteger的原始碼如下:

  1. publicclass AtomicInteger extends Number implements java.io.Serializable {  
  2.     privatestaticfinallong serialVersionUID = 6214790243416807050L;  
  3.     // setup to use Unsafe.compareAndSwapInt for updates 使用Unsafe類的CAS操作實現更新
  4.     privatestaticfinal Unsafe unsafe = Unsafe.getUnsafe();  
  5.     privatestaticfinallong valueOffset;  
  6.     ......  
  7.     //volatile保證可見性
  8.     privatevolatileint value;  
  9.     //構造器