used for simple flags to indicate something has occurred, or for writing lock-free algorithms that incorporate
use of the atomic variables mentioned in Section 25.9.1 on page 733.
An additional effect of making a variable volatile is that reads and writes are guaranteed to be atomic. This
extends the basic atomicity guarantee to cover long and double variables.
A few other synchronization actions help make multithreading work nicely:
Starting a thread synchronizes with the first action performed by that thread when it executes. This
ensures that a newly started thread sees any data that was initialized by the creating threadincluding
the thread's own fields.
•
The final action of a thread synchronizes with any action that detects that the thread has
terminatedsuch as calling isAlive or invoking join on that thread. This ensures, for example, that
if you join a thread you can see all data written by that thread before it terminatedsuch as the results of
its computation.
•
Interrupting a thread synchronizes with any other action that determines that the thread has been
interrupted, such as the thread throwing InterruptedException or another thread invoking
isInterrupted on the thread.
•
The write of the default value (zero, null, or false) to any field synchronizes with the first action in
any thread. This ensures that even in incorrectly synchronized programs a thread will never see
arbitrary values in fieldseither a specific value written by some thread will be seen or the default value
of the field will be seen.
•
14.10.2. Final Fields and Security
We described in Section 2.2.3 on page 46 how final fields are used to define immutable values; indeed you
can use final fields to define immutable objects. There is a common misconception that shared access to
immutable objects does not require any synchronization because the state of the object never changes. This is
a misconception in general because it relies on the assumption that a thread will be guaranteed to see the
initialized state of the immutable object, and that need not be the case. The problem is that, while the shared
object is immutable, the reference used to access the shared object is itself shared and often
mutableconsequently, 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. For example, suppose
one thread creates a String object and stores a reference to it in a static field. A second thread then uses that
reference to access the string. There is no guarantee, based on what we've discussed so far, that the values
written by the first thread when constructing the string will be seen by the second thread when it accesses the
string.
The memory model defines the semantics for multithreaded programs and tells you what you need to do to
correctly synchronize your programs. But additionally, you need safeguards that ensure that incorrectly
synchronized programs cannot violate the integrity of the language, or the virtual machine implementation, or
the security architecture that prevents sensitive APIs from being misusedsee "Security" on page 677. These
safeguards come in the form of additional rules in the memory model covering the use of final fields.
The first rule for final fields covers the situation we described with the shared string. Basically, the rule states
that if a reference to an object is stored after the object has been constructed, then any thread that reads that
reference is guaranteed to see initialized values for the object's final fields. Note that there is no guarantee
concerning non-final fields of the object that are read without synchronization.
The second rule expands on the first to apply transitively to objects reachable via final fields. There is little
point being guaranteed to see a reference stored in a final field, if the fields of that object are not guaranteed to
be seen. What the second rule states, in general terms, is that if you read a reference from a final field, then
any non-final fields in the referenced object will have a value at least as recent as the value they had when the