Java多執行緒中讀寫不一致問題
阿新 • • 發佈:2021-11-28
問題:
假設有個全域性變數var初始化為0
MyThread執行緒迴圈+1
MyThread2執行緒檢測到var大於10時退出迴圈
問題來了,我們發現MyThread一直沒有退出迴圈
也就是說執行緒沒有及時重新整理記憶體
解決方法:給全域性變數新增 volatile關鍵字
Java提供了volatile來保證可見性。當一個變數被volatile修飾後,表示著執行緒本地記憶體無效,當一個執行緒修改共享變數後他會立即被更新到主記憶體中,當其他執行緒讀取共享變數時,它會直接從主記憶體中讀取。
點選檢視程式碼
abstract class ThreadMemo implements Runnable { private Thread t; protected String threadName; // public static int var = 0; volatile public static int var = 0; // 只需要新增volatile關鍵字就可以了 public ThreadMemo(String name) { threadName = name; System.out.println("Creating " + threadName); } abstract public void run(); public void start() { System.out.println("Starting " + threadName); if (t == null) { t = new Thread(this, threadName); t.start(); } } } class MyThread extends ThreadMemo { MyThread(String name) { super(name); } public void run() { var = super.var; while(true) { var = var + 1; // sleep(50); // time.sleep(50); try { Thread.sleep(50); } catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } // System.out.println("mythread 1 var: " + var); } } } class MyThread2 extends ThreadMemo { MyThread2(String name) { super(name); } public void run() { var = super.var; while(true) { if(var < 10) { // try { // Thread.sleep(1); // } catch (InterruptedException e) { // System.out.println("Thread " + threadName + " interrupted."); // } // Object o = new Object(); continue; } System.out.println("mythread2 var = " + var); break; } } } public class Test2 { // public static int var = 0; public static void main(String[] args) { ThreadMemo t1 = new MyThread("Thread-1"); ThreadMemo t2 = new MyThread2("Thread-2"); Thread a = new Thread(t1); Thread b = new Thread(t2); a.start(); b.start(); } }
然後我們發現,給讀執行緒的迴圈中新增一些語句,迴圈就能退出了
V2EX上發現相同的問題 Java 多執行緒併發,執行緒什麼時候會重新整理 "工作記憶體"
據說是遇到IO阻塞才會重新整理記憶體
個性簽名:時間會解決一切