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;
}