在java中,為了提高性能,線程一般把變量從內(nèi)存中備份一個副本到寄存器。volatile 關(guān)鍵字意思是易失性,明確表示
一個變量是會被多線程訪問的,每個線程在每次讀取都要從內(nèi)存讀取原始副本的值,而不是緩存在寄存器中的值。每次修改
都是把值寫回到內(nèi)存中。
Java語言包含兩種內(nèi)在的同步機制:同步塊(或方法)和 volatile 變量。
synchronized鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility)。互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現(xiàn)對共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個線程能夠使用該共享數(shù)據(jù)。可見性必須確保釋放鎖之前對共享數(shù)據(jù)做出的更改對于隨后獲得該鎖的另一個線程是可見的。 否則,線程看到的共享變量可能是修改前的值或不一致的值,引發(fā)嚴重問題。
volatile能夠?qū)崿F(xiàn)上述可見性,因為線程每次都是讀取原始版本的值,前一個線程的修改對后續(xù)線程來說是可見的。但volatile不能確保互斥。
volatile適用的原則:
- 對變量的寫操作不依賴于當前值。
- 該變量沒有包含在具有其他變量的不變式中。
不變式的意思是一個需要不變的規(guī)律,如起始要小于等于結(jié)束。上述2點簡單來說:即變量真正獨立于其他變量和自己以前的值 , 在這些
情況下可以使用
volatile
代替 synchronized
來簡化代碼。volatile由于不阻塞線程,在性能一般比synchronized表現(xiàn)更好。
適用volatile的幾個場景:
1、狀態(tài)標志 比如標示服務啟動或停止。
2、獨立觀察 定期 “發(fā)布” 觀察結(jié)果供程序內(nèi)部使用,
3、結(jié)合使用 volatile 和 synchronized 實現(xiàn) “開銷較低的讀-寫鎖”
@ThreadSafe
public class CheesyCounter {
private volatile int value;
// 使用volatile實現(xiàn)可見性,開銷低
public int getValue() { return value; }
// 使用synchronized實現(xiàn)互斥
public synchronized int increment() {
return value++;
}
}