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