Java並發_volatile實現可見性但不保證原子性


讀后感
  1. 介紹了volatile實現可見性的基本原理
  2. 介紹了volatile不能實現原子性的示例,volatile復合操作不能實現原子性,讀取值后在自增前改值可能被其它線程讀取並修改,自增后刷新值可能會覆蓋其它線程修改后的值
  3. 介紹了實現原子性的三種方法及示例
    1. synchronized  修飾對象
    2. ReentrantLock 使用lock()、unlock()加鎖解鎖,比synchronized功能更多,JDK6后性能和synchronized差不多
    3. AtomicInteger  使用樂觀鎖


  volatile關鍵字:

  • 能夠保證volatile變量的可見性
  • 不能保證volatile變量復合操作的原子性

  volatile如何實現內存可見性:

         深入來說:通過加入內存屏障和禁止重排序優化來實現的。

  • 對volatile變量執行寫操作時,會在寫操作后加入一條store屏障指令
  • 對volatile變量執行讀操作時,會在讀操作前加入一條load屏障指令

         通俗地講:volatile變量在每次被線程訪問時,都強迫從主內存中重讀該變量的值,而當該變量發生變化時,又會強迫線程將最新的值刷新到主內存。這樣任何時刻,不同的線程總能看到該變量的最新值。

 

         線程寫volatile變量的過程:

  • 改變線程工作內存中volatile變量副本的值
  • 將改變后的副本的值從工作內存刷新到主內存

         線程讀volatile變量的過程:

  • 從主內存中讀取volatile變量的最新值到線程的工作內存中
  • 從工作內存中讀取volatile變量的副本

         volatile不能保證volatile變量復合操作的原子性:

Java代碼   收藏代碼
  1. private int number = 0;  
  2. number++; //不是原子操作  

         它分為三步:
         讀取number的值
         將number的值加1
         寫入最新的number的值

 

          保證number自增操作的原子性:

  • 使用synchronized關鍵字
  • 使用ReentrantLock
  • 使用AtomicInteger

          使用synchronized關鍵字

Java代碼   收藏代碼
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3.   
  4. /** 
  5.  * @author InJavaWeTrust 
  6.  */  
  7. public class TestSyn implements Runnable {  
  8.   
  9.     private int number = 0;  
  10.   
  11.     public int getNumber() {  
  12.         return this.number;  
  13.     }  
  14.   
  15.     public void run() {  
  16.         increase();  
  17.     }  
  18.   
  19.     public void increase() {  
  20.         synchronized (this) {  
  21.             this.number++;  
  22.         }  
  23.     }  
  24.   
  25.     public static void main(String[] args) {  
  26.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
  27.         TestSyn syn = new TestSyn();  
  28.         for (int i = 0; i < 1000; i++) {  
  29.             exec.submit(syn);  
  30.         }  
  31.         System.out.println("number : " + syn.getNumber());  
  32.         exec.shutdown();  
  33.     }  
  34. }  

 

          使用ReentrantLock

Java代碼   收藏代碼
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantLock;  
  5. /** 
  6.  * @author InJavaWeTrust 
  7.  */  
  8. public class TestRee implements Runnable {  
  9.   
  10.     private Lock lock = new ReentrantLock();  
  11.     private int number = 0;  
  12.   
  13.     public int getNumber() {  
  14.         return this.number;  
  15.     }  
  16.   
  17.     public void run() {  
  18.         increase();  
  19.     }  
  20.   
  21.     public void increase() {  
  22.         lock.lock();  
  23.         try {  
  24.             this.number++;  
  25.         } finally {  
  26.             lock.unlock();  
  27.         }  
  28.     }  
  29.   
  30.     public static void main(String[] args) {  
  31.         TestRee ree = new TestRee();  
  32.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
  33.         for (int i = 0; i < 1000; i++) {  
  34.             exec.submit(ree);  
  35.         }  
  36.         System.out.println("number : " + ree.getNumber());  
  37.         exec.shutdown();  
  38.     }  
  39. }  

 

          使用AtomicInteger

Java代碼   收藏代碼
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.atomic.AtomicInteger;  
  4.   
  5. /** 
  6.  * @author InJavaWeTrust 
  7.  */  
  8. public class TestAtomic implements Runnable {  
  9.   
  10.     private static AtomicInteger number = new AtomicInteger(0);  
  11.   
  12.     public void run() {  
  13.         increase();  
  14.     }  
  15.   
  16.     public void increase() {  
  17.         number.getAndAdd(1);  
  18.     }  
  19.   
  20.     public static void main(String[] args) {  
  21.         TestAtomic ato = new TestAtomic();  
  22.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
  23.         for (int i = 0; i < 1000; i++) {  
  24.             exec.submit(ato);  
  25.         }  
  26.         System.out.println("number : " + number.get());  
  27.         exec.shutdown();  
  28.     }  
  29. }  





免責聲明!

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



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