Double-Checked Locking Without Volatile
ID |
java.double_check_locking |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
CWE:609, concurrency, reliability |
Description
Reports the double-checked locking pattern where the checked field is not declared volatile. Without volatile, the Java Memory Model allows the write to the field and the construction of the object to be reordered, so another thread may see a non-null reference to a partially constructed object.
Rationale
The classic double-checked locking pattern checks a field for null, enters a synchronized block, and checks again. Without volatile on the field, the JIT compiler is free to reorder the assignment and the constructor, exposing a half-initialized object to a concurrent reader.
// Bad -- field is not volatile
private Helper helper;
public Helper getHelper() {
if (helper == null) {
synchronized (this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
Remediation
Declare the field volatile, or use the initialization-on-demand holder idiom:
// Good -- volatile field
private volatile Helper helper;
public Helper getHelper() {
if (helper == null) {
synchronized (this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
// Better -- holder class idiom
private static class HelperHolder {
static final Helper INSTANCE = new Helper();
}
public static Helper getInstance() {
return HelperHolder.INSTANCE;
}