...
This noncompliant code example declares a shared boolean
flag
variable and provides a toggle()
method that negates the current value of flag
.
Code Block | ||
---|---|---|
| ||
final class Flag {
private boolean flag = true;
public void toggle() { // Unsafe
flag = !flag;
}
public boolean getFlag() { // Unsafe
return flag;
}
}
|
...
The toggle()
method may also 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;
}
}
|
...
Declaring flag
volatile also fails to solve the problem:
Code Block | ||
---|---|---|
| ||
final class Flag {
private volatile boolean flag = true;
public void toggle() { // Unsafe
flag ^= true;
}
public boolean getFlag() { // Safe
return flag;
}
}
|
...
This compliant solution declares both the toggle()
and getFlag()
methods as synchronized.
Code Block | ||
---|---|---|
| ||
final class Flag {
private boolean flag = true;
public synchronized void toggle() {
flag ^= true; // Same as flag = !flag;
}
public synchronized boolean getFlag() {
return flag;
}
}
|
...
In this compliant solution, the getFlag()
method is not synchronized, and flag
is declared as volatile. This solution is compliant because the read of flag
in the getFlag()
method is an atomic operation and the volatile qualification assures visibility. The toggle()
method still requires synchronization because it performs a nonatomic operation.
Code Block | ||
---|---|---|
| ||
final class Flag {
private volatile boolean flag = true;
public synchronized void toggle() {
flag ^= true; // Same as flag = !flag;
}
public boolean getFlag() {
return flag;
}
}
|
...
This compliant solution uses a read-write lock to ensure atomicity and visibility.
Code Block | ||
---|---|---|
| ||
final class Flag {
private boolean flag = true;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public void toggle() {
writeLock.lock();
try {
flag ^= true; // Same as flag = !flag;
} finally {
writeLock.unlock();
}
}
public boolean getFlag() {
readLock.lock();
try {
return flag;
} finally {
readLock.unlock();
}
}
}
|
...
This compliant solution declares flag
to be of type AtomicBoolean
.
Code Block | ||
---|---|---|
| ||
import java.util.concurrent.atomic.AtomicBoolean;
final class Flag {
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;
}
}
|
...
In this noncompliant code example, multiple threads can invoke the setValues()
method to set the a
and b
fields. Because this class fails to test for integer overflow, users of the Adder
class must ensure that the arguments to the setValues()
method can be added without overflow. (See rule NUM00-J. Detect or prevent integer overflow for more information.)
Code Block | ||
---|---|---|
| ||
final class Adder {
private int a;
private int b;
public int getSum() {
return a + b;
}
public void setValues(int a, int b) {
this.a = a;
this.b = b;
}
}
|
...
In this noncompliant code example, a
and b
are replaced with atomic integers.
Code Block | ||
---|---|---|
| ||
final class Adder {
private final AtomicInteger a = new AtomicInteger();
private final AtomicInteger b = new AtomicInteger();
public int getSum() {
return a.get() + b.get();
}
public void setValues(int a, int b) {
this.a.set(a);
this.b.set(b);
}
}
|
...
This compliant solution synchronizes the setValues()
and getSum()
methods to ensure atomicity.
Code Block | ||
---|---|---|
| ||
final class Adder {
private int a;
private int b;
public synchronized int getSum() {
// Check for overflow
return a + b;
}
public synchronized void setValues(int a, int b) {
this.a = a;
this.b = b;
}
}
|
...
Some available static analysis tools can detect the instances of nonatomic update of a concurrently shared value. The result of the update is determined by the interleaving of thread execution. These tools can detect the instances where thread-shared data is accessed without holding an appropriate lock, possibly causing a race condition.
Tool | Version | Description | ||||||
---|---|---|---|---|---|---|---|---|
ThreadSafe |
| Implemented |
Related Guidelines
CWE-667. Improper locking | |
| CWE-413. Improper resource locking |
| CWE-366. Race condition within a thread |
| CWE-567. Unsynchronized access to shared data in a multithreaded context |
...
[API 2006] | Class |
Item 66. Synchronize access to shared mutable data | |
2.3, Locking | |
[JLS 2005] | |
| §17.4.5, Happens-Before Order |
| §17.4.3, Programs and Program Order |
| §17.4.8, Executions and Causality Requirements |
[Lea 2000] | Section 2.2.7, The Java Memory Model |
| Section 2.1.1.1, Objects and Locks |