Java Reference
In-Depth Information
10.1.3. Deadlocks Between Cooperating Objects
Multiple lock acquisition is not always as obvious as in
LeftRightDeadlock
or
trans-
ferMoney
; the two locks need not be acquired by the same method. Consider the cooperat-
ing classes in
Listing 10.5
, which might be used in a taxicab dispatching application.
Taxi
represents an individual taxi with a location and a destination;
Dispatcher
represents a
fleet of taxis.
While no method
explicitly
acquires two locks, callers of
setLocation
and
getImage
can acquire two locks just the same. If a thread calls
setLocation
in response to an update
from a GPS receiver, it first updates the taxi's location and then checks to see if it has reached
its destination. If it has, it informs the dispatcher that it needs a new destination. Since
both
setLocation
and
notifyAvailable
are
synchronized
, the thread calling
setLocation
acquires the
Taxi
lock and then the
Dispatcher
lock. Similarly, a thread
calling
getImage
acquires the
Dispatcher
lock and then each
Taxi
lock (one at at
time). Just as in
LeftRightDeadlock
, two locks are acquired by two threads in different
orders, risking deadlock.
It was easy to spot the deadlock possibility in
LeftRightDeadlock
or
transfer-
Money
by looking for methods that acquire two locks. Spotting the deadlock possibility in
Taxi
and
Dispatcher
is a little harder: the warning sign is that an
alien
method (defined
on page 40) is being called while holding a lock.
Invoking an alien method with a lock held is asking for liveness trouble. The alien method
might acquire other locks (risking deadlock) or block for an unexpectedly long time, stalling
other threads that need the lock you hold.
10.1.4. Open Calls
Of course,
Taxi
and
Dispatcher
didn't
know
that they were each half of a deadlock wait-
ing to happen. And they shouldn't have to; a method call is an abstraction barrier intended to
shield you from the details of what happens on the other side. But because you don't know
what is happening on the other side of the call,
calling an alien method with a lock held is
difficult to analyze and therefore risky.
Calling a method with no locks held is called an
open call
[CPJ 2.4.1.3], and classes that
rely on open calls are more well-behaved and composable than classes that make calls with