Volatile關鍵字 可以確保在應用程式中的可見性,支持變量直接寫入到主記憶體(main memory)。
來自《Thinking in Java , edtion 4》的解釋
The volatile keyword also ensures visibility across the application. If you declare a field to >be volatile, this means that as soon as a write occurs for that field, all reads will see the >change. This is true even if local caches are involved—volatile fields are immediately written >through to main memory, and reads occur from main memory.
Volatile的主要功能:
第一:提供可見性
當一個變量的前面被加上Volatile後,當它的被修改就會即時被更新到主記憶體(main memory)。
當有其他thread想存取這變量的最新值,都可以在主記憶體(main memory)中看到。
要做到這效果還有其他方法,就是利用Synchronized + Lock來實現。
但不在這裡詳述,會再另一篇文章作講解。
public class WorkerThread extends Thread {
private boolean isRunning = true;
@Override
public void run() {
while (isRunning) {
// execute a task
}
}
public void stopWorker() {
isRunning = false;
}
}
在上面的例子可以看到它有兩個tasks分別是run() 和stopWorker() 。
變量isRunning 的預設值true,所以可以執行run() 內的動作。
而stopWorker() 則是可以控制能否執行run() ,因為它可以修改isRunning 的值。
但在這個例子中,即使修改了isRunning 的值為false,run()都仍然有機會執行。
重點在於run()能否在主記憶體中獲得最新的isRunning 的值。
為了確保run()能獲得最新的isRunning 的值,我們可以利用Volatile關鍵字來解決。
在變量isRunning前加上volatile:
public class WorkerThread extends Thread {
private volatile boolean isRunning = true;
@Override
public void run() {
while (isRunning) {
// execute a task
}
}
public void stopWorker() {
isRunning = false;
}
}
第二:保證初始化對象時的次序(happens-before relationship)
public class MyWorker {
private int workerNumber;
public MyWorker (int workerNumber) {
this.workerNumber = workerNumber;
}
public int getWorkerNumber () {
return workerNumber;
}
}
在上面的例子,我們可以實例化MyWorker class (同時假設這是其中一個Thread,名字叫Thread 1)
MyWorker workerInstance = new MyWorker (1);
當執行之上的code時,JVM 會依以下次序操作:
1: 分配記憶體的空間
2: 將分配到的記憶體的空間(記憶體的空間的地址)給予實例workerInstance
(workerInstance 不再是null了)
3: 將值寫入workerInstance
不過在第2個與第3個步驟之間會有機會遇到其他Thread正在執行以下程式:
if(workerInstance!= null){
System.out.println(workerInstance.getValue());
}
所以最後由Thread 1實例化MyWorker class的結果不是1。
為了解決上述的問題,我們可以在變量workerNumber前加上volatile關鍵字。
可以保證JVM只能在完成所有寫入程序後(完成第3個步驟後)才能讀取workerInstance的值。
public class MyWorker {
private volatile int workerNumber;
public MyWorker (int workerNumber) {
this.workerNumber = workerNumber;
}
public int getWorkerNumber () {
return workerNumber;
}
}
參考文章/網站/書本: