Safe publication¶
ID: java/safe-publicationKind: problemSecurity severity: Severity: warningPrecision: highTags: - quality - reliability - concurrencyQuery 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 forObject isnull) 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
finalkeyword 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 thefinal 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 fromjava.util.concurrent.
Example¶
In the following example, the values ofvalue andserver_id are not safely published. The constructor creates a new object and assigns it to the fieldvalue. However, the field is not declared asvolatile orfinal, 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 valuenull. Similarly, the fieldserver_id may be observed to be0.
publicclassUnsafePublication{privateObjectvalue;privateintserver_id;publicUnsafePublication(){value=newObject();// Not safely published, other threads may see the default value nullserver_id=1;// Not safely published, other threads may see the default value 0}publicObjectgetValue(){returnvalue;}publicintgetServerId(){returnserver_id;}}
To fix this example, we declare the fieldvalue as volatile. This will ensure that all changes to the field are visible to all threads. The fieldserver_id is only meant to be written once, so we only need the write inside the constructor to be visible to other threads; declaring itfinal guarantees this:
publicclassSafePublication{privatevolatileObjectvalue;privatefinalintserver_id;publicSafePublication(){value=newObject();// Safely published as volatileserver_id=1;// Safely published as final}publicsynchronizedObjectgetValue(){returnvalue;}publicintgetServerId(){returnserver_id;}}
References¶
Java Language Specification, chapter 17:Threads and Locks.
Java concurrency package:java.util.concurrent.