...
For atomicity of a grouping of calls to independently atomic methods belonging to the thread-safe classes, see CON07-J. Do not assume that a grouping of calls to independently atomic methods is atomic.
The Java Language Specification also permits reads and writes of 64-bit values to be non-atomic though this is not an issue with most modern JVMs (see CON25-J. Ensure atomicity when reading and writing 64-bit values).
...
Code Block | ||
---|---|---|
| ||
final class Flag { private boolean flag = true; public void toggle() { // Unsafe flag = !flag; } public boolean getFlag() { // Unsafe return flag; } } |
It is prone to Execution of this code may result in a data race because the value of flag
is read, negated, and written back.
AlternativelySimilarly, the toggle()
method can use the compound assignment operator ^=
to negate the current value of flag
.
Code Block | ||
---|---|---|
| ||
final class Flag { private boolean flag = true; public void toggle() { // Unsafe flag ^= true; // Same as flag = !flag; } public boolean getFlag() { // Unsafe return flag; } } |
This attempt code is also not thread-safe. A data race exists because ^=
is a non-atomic compound operation.
Consider, for example, two threads that call toggle()
. The effect of toggling flag
twice is expected to restore it to its original value. However, the following scenario leaves flag
in the wrong incorrect state:
Time | flag= | Thread | Action |
---|---|---|---|
1 | true | t1 | reads the current value of |
2 | true | t2 | reads the current value of |
3 | true | t1 | toggles the temporary variable to false |
4 | true | t2 | toggles the temporary variable to false |
5 | false | t1 | writes the temporary variable's value to |
6 | false | t2 | writes the temporary variable's value to |
As a result, the effect of the call by t2 is not reflected in flag
; the program behaves as if the call was never made.
Noncompliant Code Example (volatile
variable)
This noncompliant code example derives from the preceding one but declares Declaring flag
as volatile . also does not help:
Code Block | ||
---|---|---|
| ||
final class Flag { private volatile boolean flag = true; public void toggle() { // Unsafe flag ^= true; } public boolean getFlag() { // Safe return flag; } } |
It is still insecure This code remains unsuitable for multithreaded use because declaring a variable as volatile does not guarantee the visibility of updates to the shared variable flag
when a compound operation is performed. In other words, the value of the write depends on the current value of the variablethat compound operations on that variable are performed atomically.
Compliant Solution (synchronization)
...