update the object. Any other (updating) thread must wait until the lock has been
released. Once the fi rst thread has fi nished its updating, it should release the lock,
making it available to other such threads. (Note that threads requiring read-only
access do not need to obtain a lock.)
One unfortunate possibility with this system, however, is that deadlock may
occur. A state of deadlock occurs when threads are waiting for events that will never
happen. Consider the example illustrated in Fig. 3.5 . Here, thread1 has a lock on
resource res1 , but needs to obtain a lock on res2 in order to complete its processing
(so that it can release its lock on res1 ). At the same time, however, thread2 has a
lock on res2 , but needs to obtain a lock on res1 in order to complete its processing.
Unfortunately, only good design can avoid such situations. In the next section, we
consider how locks are implemented in Java.
An illustration of
Locking is achieved by placing the keyword synchronized in front of the
method defi nition or block of code that does the updating.
public synchronized void updateSum(int amount)
If sum is not locked when the above method is invoked, then the lock on sum is
obtained, preventing any other thread from executing updateSum . All other threads
attempting to invoke this method must wait. Once the method has fi nished execu-
tion, the lock is released and made available to other threads. If an object has more
than one synchronized method associated with it, then only one may be active
at any given time.
In order to improve thread effi ciency and to help avoid deadlock, the following
methods are used: