Java多執行緒中volatile的場景應用
阿新 • • 發佈:2018-12-26
一、場景簡述
筆者在看多執行緒通訊相關問題時,不使用等待/通知機制實現多執行緒通訊的時候,發現b執行緒沒有與a執行緒發生正常通訊。
二、場景實現
如下是未發生正常通訊的程式碼
1、MyList類
package waitnotify; import java.util.ArrayList; import java.util.List; /** * @author: linjie * @description: 不使用等待/通知機制實現執行緒間的通訊 list類 * @create: 2018/09/24 18:46 */ public class MyList { private List list = new ArrayList(); //向list中新增資料 public void add(){ list.add("xlj"); } //返回list的大小 public int size(){ return list.size(); } }
2、執行緒類A
package waitnotify; /** * @author: linjie * @description: 不使用等待/通知機制的執行緒類A * @create: 2018/09/24 18:50 */ public class ThreadA extends Thread{ private MyList list; //構造器 public ThreadA(MyList list){ super(); System.out.println("a...."); this.list = list; } @Override public void run(){ try { for (int i = 0;i < 10;i++){ list.add(); System.out.println("添加了"+(i+1)+"個元素"); Thread.sleep(1000); } }catch (InterruptedException e){ e.printStackTrace(); } } }
3、執行緒類B
package waitnotify; /** * @author: linjie * @description: 不使用等待/通知機制的執行緒類B * @create: 2018/09/24 19:12 */ public class ThreadB extends Thread{ private MyList list; public ThreadB(MyList list){ super(); System.out.println("b...."); this.list = list; } @Override public void run(){ try{ while (true){ if (list.size() == 5){ System.out.println("==5了,執行緒b要退出了!"); throw new InterruptedException(); } } }catch (InterruptedException e){ e.printStackTrace(); } } }
4、main類
package waitnotify;
/**
* @author: linjie
* @description:不使用等待/通知機制的main類
* @create: 2018/09/24 19:20
*/
public class Test {
public static void main(String[] args){
MyList service = new MyList();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
}
執行結果如下
可以看到程式處於死迴圈,並且沒有出現 “==5了,執行緒b要退出了!”
三、場景分析
該現象與Java記憶體模型有關,Java記憶體模型如圖,可以看出每個執行緒都有一個自己的本地記憶體空間,執行緒執行時,先把變數從主記憶體讀取到執行緒自己的本地記憶體空間,然後再對該變數進行操作。然後對該變數操作完後,在某個時間再把該變數重新整理回主記憶體
所以場景程式碼中,A執行緒將list讀取到本地記憶體,修改後,再重新整理回主記憶體。
而在JVM 設定成 -server模式執行程式時,執行緒會一直在私有堆疊中讀取list大小,所以B執行緒一直無法讀取到A執行緒改變的list變數,從而處於死迴圈,並無法出現 “==5了,執行緒b要退出了!”
(圖片摘取地址在文末)
四、解決方案
線上程類B中對其變數前加volatile,作用即:它強制執行緒從主記憶體中取 volatile修飾的變數
volatile private MyList list;