Reads of shared primitive variables may not observe the latest writes to them. It is important to ensure that the accesses see the value of the latest writes. If this is not done, multiple threads may observe stale values of the shared variables and fail to act accordingly. Visibility of latest values can be ensured using volatile
or synchronization.
The use of volatile
is recommended under a very restrictive set of conditions:
- A write to a variable does not depend on its current value
- The write is not involved with writes of other variables
Accesses of primitive variables are atomic, except for the 64-bit long
and double
variables; see CON25-J. Ensure atomicity when reading and writing 64-bit values for information on sharing long
and double
variables among multiple threads.
If a shared primitive variable has these characteristics:
- A write to a variable does not depend on its current value
- The write is not involved with writes of other variables
Wiki Markup |
---|
Then the variable should be declared as {{volatile}} \[[Goetz 06|AA. Java References#Goetz 06]\]. If this is not done, multiple threads may observe stale values of the shared variables and fail to act accordingly. |
Noncompliant Code Example
...
Compliant Solution (volatile
)
This compliant solution qualifies declares the done
flag as volatile
so that updates are visible to other threads.
...
This compliant solution uses the this
object's intrinsic lock of the Class
object to ensure thread safety.
Code Block | ||
---|---|---|
| ||
final class ControlledStop implements Runnable { private boolean done = false; public void run() { while (!isDone()) { try { // ... Thread.currentThread().sleep(1000); // Do something } catch(InterruptedException ie) { // handle exception } } } protected synchronized bool isDone() { return done; } protected synchronized void shutdown() { done = true; } } |
While this is an acceptable compliant solution, it has the following disadvantages compared to marking declaring done
as {{volatile:
- Performance: The intrinsic locks cause threads to block temporarily;
volatile
incurs no blocking - Deadlock: Improper usage use of locks can lead to deadlock. Since deadlocks. Because the use of
volatile
incurs no blocking, deadlock cannot occur.
However, synchronization is a useful alternative in situations where the volatile
keyword is inappropriate, such as if a variable's new value depends on its old value. Refer to CON01-J. Do not assume that composite operations are atomic and CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic for more details.
Risk Assessment
Failing to ensure visibility of atomically modifiable shared variables can lead to a thread seeing stale values of a variable.
...