Java中volatile如何保證long和double的原子性操作


原創轉載請注明出處:https://www.cnblogs.com/agilestyle/p/11426473.html

 

關鍵字volatile的主要作用是使變量在多個線程間可見,但無法保證原子性,對於多個線程訪問同一個實例變量需要加鎖進行同步。

 1 package org.fool.java.concurrent.volatiletest;  
 2   
 3 import java.util.concurrent.ExecutorService;  
 4 import java.util.concurrent.Executors;  
 5   
 6 public class VolatileTest1 {  
 7   
 8     private static volatile int count = 0;  
 9   
10     private static void addCount() {  
11         for (int i = 0; i < 100; i++) {  
12             count++;  
13         }  
14   
15         System.out.println(Thread.currentThread().getName() + " count = " + count);  
16     }  
17   
18     public static void main(String[] args) {  
19         ExecutorService executor = Executors.newCachedThreadPool();  
20   
21         for (int i = 0; i < 100; i++) {  
22             executor.execute(new Runnable() {  
23                 @Override  
24                 public void run() {  
25                     VolatileTest1.addCount();  
26                 }  
27             });  
28         }  
29   
30         executor.shutdown();  
31     }  
32 } 

Note:

addCount()方法沒有加synchronized

Console Output

預期結果應該是10000,盡管count被volatile修飾,保證了可見性,但是count++並不是一個原子性操作,它被拆分為load、use、assign三步,而這三步在多線程環境中,use和assgin是多次出現的,但這操作是非原子性的,也就是在read和load之后,如果主內存count變量發生修改之后,線程工作內存中的值由於已經加載,不會產生對應的變化,也就是私有內存和公有內存中的變量不同步,所以計算出來的值和預期不一樣,就產生了線程安全的問題,所以需要用synchronized進行加鎖同步

 

addCount()方法用synchronized進行加鎖同步

Console Output

結果10000與預期一致 

 

所以volatile只能保證可見性不能保證原子性,但用volatile修飾long和double可以保證其操作原子性

所以從Oracle Java Spec里面可以看到:

  • 對於64位的long和double,如果沒有被volatile修飾,那么對其操作可以不是原子的。在操作的時候,可以分成兩步,每次對32位操作。
  • 如果使用volatile修飾long和double,那么其讀寫都是原子操作
  • 對於64位的引用地址的讀寫,都是原子操作
  • 在實現JVM時,可以自由選擇是否把讀寫long和double作為原子操作
  • 推薦JVM實現為原子操作 

 

Reference

http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7

http://www.cnblogs.com/louiswong/p/5951895.html

http://ifeve.com/volatile/

http://www.infoq.com/cn/articles/java-memory-model-4/

 


免責聲明!

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



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