A common misconception is that shared references to immutable objects are immediately visible across multiple threads as soon as they are updated. For example, a developer can mistakenly believe that a class containing fields that refer only to immutable objects is itself immutable and, consequently, thread-safe.
Section 14.10.2, "Final Fields and Security" of Java Programming Language, Fourth Edition states [[JPL 2006]]
The problem is that, while the shared object is immutable, the reference used to access the shared object is itself shared and often mutable. Consequently, a correctly synchronized program must synchronize access to that shared reference, but often programs do not do this, because programmers do not recognize the need to do it.
The String example might be good for the intro...if the long quote was not a good idea, perhaps a "For example, ..." line will help
References to both immutable and mutable objects must be made visible to all the threads. Immutable objects can be shared safely among multiple threads. However, references to mutable objects can be made visible before the objects are fully constructed. Rule TSM03-J. Do not publish partially initialized objects describes object construction and visibility issues specific to mutable objects.
Noncompliant Code Example
This noncompliant code example consists of the immutable Helper
class:
// Immutable Helper public final class Helper { private final int n; public Helper(int n) { this.n = n; } // ... }
and a mutable Foo
class:
final class Foo { private Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } }
The getHelper()
method publishes the mutable helper
field. Because the Helper
class is [immutable], it cannot be changed after it is initialized
do not replace with "after initialization"
. Furthermore, because Helper
is immutable, it is always constructed properly before its reference is made visible, in compliance with rule TSM03-J. Do not publish partially initialized objects. Unfortunately, a separate thread could observe a stale reference in the helper
field of the Foo
class.
Compliant Solution (Synchronization)
This compliant solution synchronizes the methods of the Foo
class to ensure that no thread sees a stale Helper
reference.
final class Foo { private Helper helper; public synchronized Helper getHelper() { return helper; } public synchronized void setHelper(int num) { helper = new Helper(num); } }
The immutable Helper
class remains unchanged.
Compliant Solution (volatile
)
References to immutable member objects can be made visible by declaring them volatile.
final class Foo { private volatile Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } }
The immutable Helper
class remains unchanged.
Compliant Solution (java.util.concurrent
Utilities)
This compliant solution wraps the mutable reference to the immutable Helper
object within an AtomicReference
wrapper that can be updated atomically.
final class Foo { private final AtomicReference<Helper> helperRef = new AtomicReference<Helper>(); public Helper getHelper() { return helperRef.get(); } public void setHelper(int num) { helperRef.set(new Helper(num)); } }
The immutable Helper
class remains unchanged.
Sometimes I use the area before the risk assessment as a summary area for other CSs that can simply be mentioned to avoid redundancy, or CSs that are worth considering but have limitations which preclude us from recommending them. Basically general advice so that the implementer is not left wondering with a "what if I use ..." question. You deleted the line about making Helper immutable so where could such advice go?
Risk Assessment
The assumption that classes that contain only references to immutable objects are themselves immutable is misleading and can cause serious thread-safety issues.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
VNA01-J |
low |
probable |
medium |
P4 |
L3 |
Bibliography
[[API 2006]] |
|
[[JPL 2006]] |
Section 14.10.2, "Final Fields and Security" |
Issue Tracking
Review List
null [!The CERT Oracle Secure Coding Standard for Java^button_arrow_up.png!] null