Java Reference
In-Depth Information
cases, the program's behavior cannot be trusted—sometimes the program will produce the
correct results, and sometimes it won't, and there won't be any indication that the shared
object was manipulated incorrectly.
The problem can be solved by giving only one thread at a time exclusive access to code
that accesses the shared object. During that time, other threads desiring to access the object
are kept waiting. When the thread with exclusive access finishes accessing the object, one of
the waiting threads is allowed to proceed. This process, called thread synchronization , coor-
dinates access to shared data by multiple concurrent threads. By synchronizing threads in this
manner, you can ensure that each thread accessing a shared object excludes all other threads
from doing so simultaneously—this is called mutual exclusion .
23.4.1 Immutable Data
Actually, thread synchronization is necessary only for shared mutable data , i.e., data that
may change during its lifetime. With shared immutable data that will not change, it's not
possible for a thread to see old or incorrect values as a result of another thread's manipu-
lation of that data.
When you share immutable data across threads, declare the corresponding data fields
final to indicate that the values of the variables will not change after they're initialized.
This prevents accidental modification of the shared data, which could compromise thread
safety. Labeling object references as final indicates that the reference will not change, but it
does not guarantee that the referenced object is immutable—this depends entirely on the object's
properties. However, it's still good practice to mark references that will not change as
final .
Software Engineering Observation 23.3
Always declare data fields that you do not expect to change as final . Primitive variables that
are declared as final can safely be shared across threads. An object reference that's declared
as final ensures that the object it refers to will be fully constructed and initialized before it's
used by the program, and prevents the reference from pointing to another object.
23.4.2 Monitors
A common way to perform synchronization is to use Java's built-in monitors . Every object
has a monitor and a monitor lock (or intrinsic lock ). The monitor ensures that its object's
monitor lock is held by a maximum of only one thread at any time. Monitors and monitor
locks can thus be used to enforce mutual exclusion. If an operation requires the executing
thread to hold a lock while the operation is performed, a thread must acquire the lock before
proceeding with the operation. Other threads attempting to perform an operation that re-
quires the same lock will be blocked until the first thread releases the lock , at which point
the blocked threads may attempt to acquire the lock and proceed with the operation.
To specify that a thread must hold a monitor lock to execute a block of code, the code
should be placed in a synchronized statement . Such code is said to be guarded by the
monitor lock; a thread must acquire the lock to execute the guarded statements. The mon-
itor allows only one thread at a time to execute statements within synchronized state-
ments that lock on the same object, as only one thread at a time can hold the monitor lock.
The synchronized statements are declared using the synchronized keyword :
 
 
 
Search WWH ::




Custom Search