作為解決上篇中提到的多線程環境下的memory visibility問題,java提供了一種比同步(synchronization)機制相對弱的一種形式--Volatile 變量,來確保更新一個多線程共享變量可以以一種可預告的方式通知其他線程。volatile變量并不緩存到寄存器中(registers)或者緩存到其他處理器(多處理器環境,register只能被包含它的處理器看見)看不見的地方,因此對于volatile變量的讀取總是會返回最新的結果(因為沒有使用緩存)
訪問volatile變量不需要加鎖,因此不會導致當前執行的線程堵塞,所以volatile變量相對于synchronized來說是一種輕量級的同步機制。
顯然因為沒有利用緩存,所以比起非voiatile變量,在當前的處理器架構下,讀取性能會略有損失
原文:
The Java language also provides an alternative, weaker form of synchronization, volatile variables, to ensure that updates to a variable are propagated predictably to other threads. When a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations. Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread.
Yet accessing a volatile variable performs no locking and so cannot cause the executing thread to block, making volatile variables a lighter-weight synchronization mechanism than synchronized.
Volatile reads are only slightly more expensive than nonvolatile reads on most current processor architectures.
So from a memory visibility perspective, writing a volatile variable is like exiting a synchronized block and reading a volatile variable is like entering a synchronized block. However, we do not recommend relying too heavily on volatile variables for visibility; code that relies on volatile variables for visibility of arbitrary state is more fragile and harder to understand than code that uses locking.
從memory visibility的方面來看,寫入一個volatile變量就像離開一個同步塊,而讀取volatile變量就像進入一個同步塊。盡管如此,建議不要太多依賴與volatile變量,因為這樣會導致代碼比起用同步塊更難以理解
Use volatile variables only when they simplify implementing and verifying your synchronization policy; avoid using volatile variables when veryfing correctness would require subtle reasoning about visibility. Good uses of volatile variables include ensuring the visibility of their own state, that of the object they refer to, or indicating that an important lifecycle event
(such as initialization or shutdown) has occurred.
The most common use for volatile variables is as a completion, interruption, or status flag。
Volatile variables can be used for other kinds of state information, but more care is required when attempting this. For example, the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee
that the variable is written only from a single thread.
結論:Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility.You can use volatile variables only when all the following criteria are met:
?? Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
?? The variable does not participate in invariants with other state variables; and
?? Locking is not required for any other reason while the variable is being accessed.