...
The Java Language Specification also permits reads and writes of 64-bit values to be non-atomic (see CON25-J. Ensure atomicity when reading and writing 64-bit values).
Noncompliant Code Example (
...
logical negation)
This noncompliant code example declares a shared boolean
variable flag
and provides a toggle()
method that negates the current value of flag
.
...
Execution of this code may result in a data race because the value of flag
is read, negated, and written back.
Similarly, 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 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 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 |
...
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 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 (bitwise negation)
Similarly, 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 code is also not thread-safe. A data race exists because ^=
is a non-atomic compound operation.
Noncompliant Code Example (volatile
)
Declaring flag
as volatile also does not help:
...
The second execution order involves the same operations, just that t2 starts and finishes before t1.
Compliance with the guideline CON04-J. Synchronize using an internal private final lock object can reduce the likelihood of misuse by ensuring that untrusted callers cannot access the lock object.
Compliant Solution (volatile-read, synchronized-write)
...
Note that declaring the variables as volatile
does not resolve the issue because these compound operations involve reads and writes of multiple variables. Also, this code does not
This code also fails to prevent integer overflow. See INT00-J. Perform explicit range checking to ensure integer operations do not overflow for more information.
...