...
A
...
common
...
misconception
...
is
...
that
...
shared
...
references
...
to
...
...
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 [JPL 2006] states:
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.
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. 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:
Code Block | ||
---|---|---|
| ||
" states \[[JPL 06|AA. Java References#JPL 06]\]: {quote} 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. {quote} {mc} 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 {mc} References to both immutable and mutable objects must be made visible to all the threads. Immutable objects can be safely shared amongst multiple threads, however, mutable objects may not be fully constructed when their references are made visible. The guideline [CON26-J. Do not publish partially initialized objects] discusses object construction and visibility issues specific to mutable objects. h2. Noncompliant Code Example This noncompliant code example consists of an immutable class {{Helper}}: {code} // Immutable Helper public final class Helper { private final int n; public Helper(int n) { this.n = n; } // ... } {code} |
and
...
a
...
mutable Foo
class:
Code Block | ||
---|---|---|
| ||
class {{Foo}}: {code:bgColor=#FFCCCC} final class Foo { private Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } } {code} The {{ |
The getHelper()
...
method
...
publishes
...
the
...
mutable
...
helper
...
field.
...
Because
...
the
...
Helper
...
class
...
is
...
...
,
...
it
...
cannot
...
be
...
changed
...
after
...
it
...
is
...
initialized.
Furthermore, because Helper
is immutable, it is always constructed properly before its reference is made visible, in compliance with 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:
Code Block | ||
---|---|---|
| ||
{mc} do not replace with "after initialization" {mc}. Furthermore, because {{Helper}} is immutable, it is always properly constructed before its reference is made visible, in compliance with [CON26-J. Do not publish partially initialized objects]. Unfortunately, a separate thread might observe a stale reference in the {{helper}} field of class {{Foo}}. h2. Compliant Solution (synchronization) This compliant solution synchronizes the methods of class {{Foo}} to ensure that no thread sees a stale {{Helper}} reference. {code:bgColor=#CCCCFF} final class Foo { private Helper helper; public synchronized Helper getHelper() { return helper; } public synchronized void setHelper(int num) { helper = new Helper(num); } } {code} |
The
...
immutable
...
Helper
...
class
...
remains
...
unchanged.
...
Compliant
...
Solution
...
(
...
volatile
...
)
...
References
...
to
...
immutable
...
member
...
objects
...
can
...
be
...
made
...
visible
...
by
...
declaring
...
them volatile:
Code Block | ||
---|---|---|
| ||
{{volatile}}. {code:bgColor=#CCCCFF} final class Foo { private volatile Helper helper; public Helper getHelper() { return helper; } public void setHelper(int num) { helper = new Helper(num); } } {code} |
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:
Code Block | ||
---|---|---|
| ||
}} utilities) This compliant solution wraps the immutable {{Helper}} object within an {{AtomicReference}} wrapper that may be updated atomically. {code:bgColor=#CCCCFF} 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)); } } {code} |
The
...
immutable
...
Helper
...
class
...
remains
...
unchanged.
Risk Assessment
The incorrect assumption that classes that contain only references to immutable objects are themselves immutable can cause serious thread-safety issues.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
VNA01-J | Low | Probable | Medium | P4 | L3 |
Automated Detection
Some static analysis tools are capable of detecting violations of this rule.
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
ThreadSafe |
| CCE_SL_INCONSISTENT | Implemented | ||||||
SonarQube |
| S2886 | Getters and setters should be synchronized in pairs |
Bibliography
Issue Tracking
Tasklist | ||||
---|---|---|---|---|
| ||||
||Completed||Priority||Locked||CreatedDate||CompletedDate||Assignee||Name||
|F|M|F|1270826173609| |dmohindr|"Unfortunately, a separate thread -could- *can* observe a stale reference in the helper field of the Foo class."|
|T|M|F|1270826698362|1271441478121|svoboda|"This compliant solution synchronizes the methods of *class* Foo -class- " (it sounds strange with class occuring after Foo)|
|
...