Java Reference
In-Depth Information
For each mutable state variable that may be accessed by more than one thread, all accesses to
that variable must be performed with the same lock held. In this case, we say that the variable
is guarded by that lock.
In SynchronizedFactorizer in Listing 2.6 , lastNumber and lastFactors are
guarded by the servlet object's intrinsic lock; this is documented by the @GuardedBy an-
notation.
There is no inherent relationship between an object's intrinsic lock and its state; an object's
fields need not be guarded by its intrinsic lock, though this is a perfectly valid locking con-
vention that is used by many classes. Acquiring the lock associated with an object does not
prevent other threads from accessing that object—the only thing that acquiring a lock pre-
vents any other thread from doing is acquiring that same lock. The fact that every object has
a built-in lock is just a convenience so that you needn't explicitly create lock objects. [9] It is
up to you to construct lockingprotocols or synchronizationpolicies that let you access shared
state safely, and to use them consistently throughout your program.
Every shared, mutable variable should be guarded by exactly one lock. Make it clear to main-
tainers which lock that is.
A common locking convention is to encapsulate all mutable state within an object and to
protect it from concurrent access by synchronizing any code path that accesses mutable state
using the object's intrinsic lock. This pattern is used by many thread-safe classes, such as
Vector and other synchronized collection classes. In such cases, all the variables in an ob-
ject's state are guarded by the object's intrinsic lock. However, there is nothing special about
this pattern, and neither the compiler nor the runtime enforces this (or any other) pattern of
locking. [10] It is also easy to subvert this locking protocol accidentally by adding a new
method or code path and forgetting to use synchronization.
Not all data needs to be guarded by locks—only mutable data that will be accessed from mul-
tiple threads. In Chapter 1 , we described how adding a simple asynchronous event such as
a TimerTask can create thread safety requirements that ripple throughout your program,
especially if your program state is poorly encapsulated. Consider a single-threaded program
that processes a large amount of data. Single-threaded programs require no synchronization,
because no data is shared across threads. Now imagine you want to add a feature to create
Search WWH ::




Custom Search