AtomicReference 和 volatile 的區別


首先volatile是java中關鍵字用於修飾變量,AtomicReference是並發包java.util.concurrent.atomic下的類。
首先volatile作用,當一個變量被定義為volatile之后,看做“程度較輕的 synchronized”,具備兩個特性:
1.保證此變量對所有線程的可見性(當一條線程修改這個變量值時,新值其他線程立即得知)
2.禁止指令重新排序
注意volatile修飾變量不能保證在並發條件下是線程安全的,因為java里面的運算並非原子操作。
java.util.concurrent.atomic工具包,支持在單個變量上解除鎖的線程安全編程。其基本的特性就是在多線程環境下,當有多個線程同時執行這些類的實例包含的方法時,具有排他性,即當某個線程進入方法,執行其中的指令時,不會被其他線程打斷,而別的線程就像自旋鎖一樣,一直等到該方法執行完成,才由JVM從等待隊列中選擇一個另一個線程進入,這只是一種邏輯上的理解。

volatile是不能保證原子性的, 寫了一點junit. 這里使用了包裝類Integer, 來驗證 對引用操作 的原子性. 可以看到使用了AtomicReference可以保證結果是正確的.

 1     private static volatile Integer num1 = 0;
 2     private static AtomicReference<Integer> ar=new AtomicReference<Integer>(num1);
 3 
 4     @Test
 5     public void dfasd111() throws InterruptedException{
 6         for (int i = 0; i < 1000; i++) {
 7             new Thread(new Runnable(){
 8                 @Override
 9                 public void run() {
10                     for (int i = 0; i < 10000; i++)
11                         while(true){
12                             Integer temp=ar.get();
13                             if(ar.compareAndSet(temp, temp+1))break;
14                         }
15                 }       
16             }).start();
17         }
18         Thread.sleep(10000);
19         System.out.println(ar.get()); //10000000
20     }
21         
22     @Test
23     public void dfasd1112() throws InterruptedException{
24         for (int i = 0; i < 1000; i++) {
25             new Thread(new Runnable(){
26                 @Override
27                 public void run() {
28                     for (int i = 0; i < 10000; i++) {
29                         num1=num1++;
30                     }
31                 }       
32             }).start();
33         }
34         Thread.sleep(10000);
35         System.out.println(num1); //something like 238981
36     }


如果想讓運算具有原子性, 請使用:

AtomicInteger

AtomicLong

類似i++這樣的"讀-改-寫"復合操作(在一個操作序列中, 后一個操作依賴前一次操作的結果), 在多線程並發處理的時候會出現問題, 因為可能一個線程修改了變量, 而另一個線程沒有察覺到這樣變化, 當使用原子變量之后, 則將一系列的復合操作合並為一個原子操作,從而避免這種問題, i++=>i.incrementAndGet()
原子變量只能保證對一個變量的操作是原子的, 如果有多個原子變量之間存在依賴的復合操作, 也不可能是安全的, 另外一種情況是要將更多的復合操作作為一個原子操作, 則需要使用synchronized將要作為原子操作的語句包圍起來. 因為涉及到可變的共享變量(類實例成員變量)才會涉及到同步, 否則不必使用synchronized


免責聲明!

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



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