多線程-Java原子變量-java.util.concurrent.atomic.*

在看下debug下面代碼的時候發現了sun.misc.Unsafe這個類,居然不是javaSE的一部分,說可能會在將來的版本刪除掉,不過現在不是還有麼,那就看看吧

源碼地址:http://www.docjar.com/docs/api/sun/misc/Unsafe.html

附一篇文章:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

這篇文章的結論是:Although, Unsafe has a bunch of useful applications, never use it.

=====================================華麗的分割線==================================

轉載地址:http://blog.csdn.net/hong0220/article/details/38958121

一個沒有併發控制的計數器:

[java] view plaincopy
  1. public class Counter implements Runnable {  
  2.     private static int count;  
  3.       
  4.     public void run() {  
  5.         System.out.println(Thread.currentThread().getName()   
  6.                 + ":" + (++count));  
  7.     }  
  8.       
  9.     public static void main(String[] args){  
  10.         Counter counter = new Counter();  
  11.         Thread t1 = new Thread(counter);  
  12.         Thread t2 = new Thread(counter);  
  13.         Thread t3 = new Thread(counter);  
  14.         Thread t4 = new Thread(counter);  
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.     }  
  20. }  

有時運行正常,但是偶爾會出現如下運行結果:

[plain] view plaincopy
  1. Thread-1:2  
  2. Thread-0:1  
  3. Thread-2:3  
  4. Thread-3:3  

這顯然和預期結果不太一樣,先用javap -verbose命令分析一下這個類,在字節碼層面上,++count等價於虛擬機順次執行如下5條字節碼指令(不考慮運行期的優化)

[plain] view plaincopy
  1. getstatic  獲取指定類的靜態域,並將其值壓入棧頂  
  2. iconst_1   將int型1推送至棧頂  
  3. iadd       將棧頂兩int型數值相加並將結果壓入棧頂  
  4. dup        複製棧頂數值並將複製值壓入棧頂  
  5. putstatic  爲指定類的靜態域賦值  

當Thread-3線程執行getstatic指令時,Thread-2線程還未執行至iadd指令,故Thread-3線程獲取的初始靜態域count的值和Thread-2線程一樣,都爲2

本質原因就是++count雖然只是一行代碼,但這一過程並非原子操作

要保證這種類型的原子操作,可以使用java.util.concurrent.atomic包下的類

[plain] view plaincopy
  1. 軟件包 java.util.concurrent.atomic   
  2. 類的小工具包,支持在單個變量上解除鎖的線程安全編程。  

示例如下:

[java] view plaincopy
  1. public class Counter implements Runnable {  
  2.     private final AtomicInteger count = new AtomicInteger(0);  
  3.       
  4.     public void run() {  
  5.         System.out.println(Thread.currentThread().getName()   
  6.                 + ":" + count.incrementAndGet());  
  7.     }  
  8.       
  9.     public static void main(String[] args){  
  10.         Counter counter = new Counter();  
  11.         Thread t1 = new Thread(counter);  
  12.         Thread t2 = new Thread(counter);  
  13.         Thread t3 = new Thread(counter);  
  14.         Thread t4 = new Thread(counter);  
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.     }  
  20. }  

看看源代碼中究竟是如何實現的

[java] view plaincopy
  1. private volatile int value;  
  2.   
  3. public AtomicInteger(int initialValue) {  
  4.     value = initialValue;  
  5. }  
  6.   
  7. public final int incrementAndGet() {  
  8.     for (;;) {  
  9.         int current = get();  
  10.         int next = current + 1;  
  11.         if (compareAndSet(current, next))  
  12.             return next;  
  13.     }  
  14. }  
  15.   
  16. /** 
  17.     * Atomically sets the value to the given updated value 
  18.     * if the current value {@code ==} the expected value. 
  19.     * 
  20.     * @param expect the expected value 
  21.     * @param update the new value 
  22.     * @return true if successful. False return indicates that 
  23.     * the actual value was not equal to the expected value. 
  24.     */  
  25. public final boolean compareAndSet(int expect, int update) {  
  26.     return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
  27. }  
  28.       
  29. public final int get() {  
  30.   return value;  
  31. }  

是不是和樂觀鎖很像,如果結果符合預期結果,就將結果返回,否則不斷進行重試,並沒有進行同步,兼顧了安全性和性能

java.util.concurrent.atomic包下還有很多類,使用這些類可以保證對這些類的諸如“獲取-更新”操作是原子性的,從而避發生競態條件

[plain] view plaincopy
  1. AtomicBoolean 可以用原子方式更新的 boolean 值。   
  2. AtomicInteger 可以用原子方式更新的 int 值。   
  3. AtomicIntegerArray 可以用原子方式更新其元素的 int 數組。   
  4. AtomicIntegerFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile int 字段進行原子更新。   
  5. AtomicLong 可以用原子方式更新的 long 值。   
  6. AtomicLongArray 可以用原子方式更新其元素的 long 數組。   
  7. AtomicLongFieldUpdater<T> 基於反射的實用工具,可以對指定類的指定 volatile long 字段進行原子更新。   
  8. AtomicMarkableReference<V> AtomicMarkableReference 維護帶有標記位的對象引用,可以原子方式對其進行更新。   
  9. AtomicReference<V> 可以用原子方式更新的對象引用。   
  10. AtomicReferenceArray<E> 可以用原子方式更新其元素的對象引用數組。   
  11. AtomicReferenceFieldUpdater<T,V> 基於反射的實用工具,可以對指定類的指定 volatile 字段進行原子更新。   
  12. AtomicStampedReference<V> AtomicStampedReference 維護帶有整數“標誌”的對象引用,可以用原子方式對其進行更新。   
發佈了42 篇原創文章 · 獲贊 3 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章