CodeQL documentation

Safe publication

ID: java/safe-publication
Kind: problem
Security severity: 
Severity: warning
Precision: high
Tags:
   - quality
   - reliability
   - concurrency
Query suites:
   - java-code-quality.qls

Click to see the query in the CodeQL repository

In a thread-safe class, values must be published safely to avoid inconsistent or unexpected behavior caused by visibility issues between threads. If a value is not safely published, one thread may see a stale or partially constructed value written by another thread, leading to subtle concurrency bugs.

In particular, values of primitive types should not be initialised to anything but their default values (which for Object is null) unless this happens in a static context.

Techniques for safe publication include:

  • Using synchronized blocks or methods to ensure that a value is fully constructed before it is published.

  • Using volatile fields to ensure visibility of changes across threads.

  • Using thread-safe collections or classes that provide built-in synchronization, such as are found in java.util.concurrent.

  • Using the final keyword to ensure that a reference to an object is safely published when the object is constructed.

Recommendation

Choose a safe publication technique that fits your use case. If the value only needs to be written once, say for a singleton, consider using the final keyword. If the value is mutable and needs to be shared across threads, consider using synchronized blocks or methods, or using a thread-safe collection from java.util.concurrent.

Example

In the following example, the values of value and server_id are not safely published. The constructor creates a new object and assigns it to the field value. However, the field is not declared as volatile or final, and there are no synchronization mechanisms in place to ensure that the value is fully constructed before it is published. A different thread may see the default value null. Similarly, the field server_id may be observed to be 0.

public class UnsafePublication {
    private Object value;
    private int server_id;

    public UnsafePublication() {
        value = new Object(); // Not safely published, other threads may see the default value null
        server_id = 1; // Not safely published, other threads may see the default value 0
    }

    public Object getValue() {
        return value;
    }

    public int getServerId() {
        return server_id;
    }
}

To fix this example, we declare the field value as volatile. This will ensure that all changes to the field are visible to all threads. The field server_id is only meant to be written once, so we only need the write inside the constructor to be visible to other threads; declaring it final guarantees this:

public class SafePublication {
    private volatile Object value;
    private final int server_id;

    public SafePublication() {
        value = new Object(); // Safely published as volatile
        server_id = 1; // Safely published as final
    }

    public synchronized Object getValue() {
        return value;
    }

    public int getServerId() {
        return server_id;
    }
}

References

  • © GitHub, Inc.
  • Terms
  • Privacy