...
This noncompliant code example declares a shared boolean
variable flag
and uses an optimization in the toggle()
method which negates the current value of flag
.
Code Block | ||
---|---|---|
| ||
class Flag {
private boolean flag = true;
public void toggle() { // unsafe
flag = !flag;
}
public boolean getFlag() { // unsafe
return flag;
}
}
|
This solution clearly has a race condition because the value of flag
is read, negated, and written.
Alternatively, the assignment operator ^=
can be used by the toggle()
method to negate the current value of the flag
.
Code Block | ||
---|---|---|
| ||
class FooFlag { private boolean flag = true; public void toggle() { // unsafe flag ^= true; // same as flag = !flag; } public boolean getFlag() { // unsafe return flag; } } |
However, this code is This solution is also not thread-safe. Multiple threads may not observe the latest state of the flag
A race condition exists because ^=
constitutes is a non-atomic compound operation.
For Consider, for example, consider two threads that call toggle()
. Theoretically the effect of toggling flag
twice should restore it to its original value. But the following scenario could occur, leaving flag
in the wrong state.
...
Code Block | ||
---|---|---|
| ||
class FooFlag { private volatile boolean flag = true; public void toggle() { // unsafe flag ^= true; } public boolean getFlag() { // safe return flag; } } |
...
Code Block | ||
---|---|---|
| ||
class FooFlag { private boolean flag = true; public synchronized void toggle() { flag ^= true; // same as flag = !flag; } public synchronized boolean getFlag() { return flag; } } |
...
Code Block | ||
---|---|---|
| ||
class FooFlag { private AtomicBoolean flag = new AtomicBoolean(true); public void toggle() { boolean temp; do { temp = flag.get(); } while(!flag.compareAndSet(temp, !temp)); } public AtomicBoolean getFlag() { return flag; } } |
...