1. 程式人生 > >多執行緒的共享變數的記憶體不可見性

多執行緒的共享變數的記憶體不可見性

/**
* 執行緒的開銷 : 執行緒的建立和銷燬
* 執行緒的上下文切換和排程
* 執行緒的同步
*
*
* 多執行緒的記憶體模型: 執行緒獨有的工作記憶體(執行緒快取用於提高效率)---------所有執行緒共享的主記憶體
*
* 執行緒讀取在主記憶體的成員變數(即共享變數)的過程:
* 1. 執行緒的工作記憶體會去讀取主記憶體的成員變數並儲存副本
* 2. 執行緒在工作記憶體中修改副本
* 3. 將修改後的副本的值推送給主空間並改寫主空間該成員變數的值
* 4. 主空間成員變數修改後的值將不會主動推送給其他執行緒, 這就造成了執行緒的工作記憶體的共享變數的不同步
*
* 問題: 各個執行緒的工作記憶體不可見
* 即 A執行緒先讀取共享變數a, B執行緒修改了共享變數a後為a`,推送給主記憶體並改寫, 主記憶體不會推送給A執行緒,A和B的變數會不同步
*
* 解決辦法
* synchroized可以同步值
* volatile關鍵字 會使得主記憶體的共享變數每經過一次改變都會推送給其他的執行緒, 其他執行緒會修改其副本
*
* 同步值之synchronized和volatile的區別
* synchronized塊只能使用物件作為它的引數(鎖是基於物件的),簡單型別的變數(如int、char、boolean等),不能使用synchronized來同步
* volatile用來同步簡單型別的變數,簡單型別的變數(如int、char、boolean等)
*
* 總結: 主記憶體 工作記憶體
* 共享變數 副本
* 工作記憶體中會主動去拉去主記憶體的共享變數
* 工作記憶體中的副本修改後會推送給主記憶體改寫共享變數
* volatile 會使得主記憶體修改後的共享變數推送其他執行緒
*
* 記憶體不可見的本質 : 執行緒之間有互相獨立的快取即, 當多個執行緒對共享資料進行操作時, 其操作彼此不可見
* 使用場景: 一個執行緒在讀共享變數 另一個執行緒在改寫共享變數
*
*/

public class VolatileTest {
public static void main(String[] args) throws InterruptedException {
MyTask task = new MyTask();
new Thread(task).start();

while (true){
//讀取值
//直接用執行緒快取的值 不會去主記憶體去拉取變數
if (task.isFlag()){
System.out.println("=============");
break;
}

/*
synchronized (task){
if (task.isFlag()){
System.out.println("=============");
break;
}
}*/

}
}

}



class MyTask implements Runnable{

private volatile boolean flag = false;

// 修改值
@Override
public void run() {

try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag=" + flag);
}

public boolean isFlag() {
return flag;
}
}