Threads and Locks
Java Virtual Machine can
support many threads of execution at once. These threads independently execute
code that operates on values and objects residing in a shared main memory.
Threads may be supported by having many hardware processors, by time-slicing a
single hardware processor, or by timeslicing many hardware processors.
Threads are represented by the Thread class. The only way for a
user to create a thread is to create an object of this class; each thread is associated
with such an object. A thread will start when the start() method is invoked on
the corresponding Thread object.
The behavior of threads,
particularly when not correctly synchronized, can be confusing and
counterintuitive. This chapter describes the semantics of multithreaded
programs; it includes rules for which values may be seen by a read of shared
memory that is updated by multiple threads. As the specification is similar to the
memory models for different hardware architectures, these semantics are known as
the Java programming language memory model. When no confusion can arise, we
will simply refer to these rules as "the memory model". These
semantics do not prescribe how a multithreaded program should be executed. Rather,
they describe the behaviors that multithreaded programs are allowed to exhibit.
Any execution strategy that generates only allowed behaviors is an acceptable
execution strategy.
Synchronization
The Java programming
language provides multiple mechanisms for communicating between threads. The
most basic of these methods is synchronization, which is implemented using
monitors. Each object in Java is associated with a monitor, which a thread can
lock or unlock. Only one thread at a time may hold a lock on a monitor. Any
other threads attempting to lock that monitor are blocked until they can obtain
a lock on that monitor. A thread t may lock a particular monitor multiple
times; each unlock reverses the effect of one lock operation.
The synchronized
statement computes a reference to an object; it then attempts to perform a lock
action on that object's monitor and does not proceed further until the lock
action has successfully completed. After the lock action has been performed,
the body of the synchronized statement is executed. If execution of the body is
ever completed, either normally or abruptly, an unlock action is automatically
performed on that same monitor.
A synchronized method automatically
performs a lock action when it is invoked; its body is not executed until the
lock action has successfully completed. If the method is an instance method, it
locks the monitor associated with the instance for which it was invoked (that
is, the object that will be known as this during execution of the body of the
method). If the method is static, it locks the monitor associated with the
Class object that represents the class in which the method is defined. If
execution of the method's body is ever completed, either normally or abruptly,
an unlock action is automatically performed on that same monitor.
The Java programming
language neither prevents nor requires detection of deadlock conditions.
Programs where threads hold (directly or indirectly) locks on multiple objects
should use conventional techniques for deadlock avoidance, creating
higher-level locking primitives that do not deadlock, if necessary. Other
mechanisms, such as reads and writes of volatile variables and the use of
classes in the java.util.concurrent package, provide alternative ways of synchronization.