THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

And when you run the program, you might get the following output before the program "hangs":


Thread1 in jareth.hug() trying to invoke cory.hugBack()
Thread2 in cory.hug() trying to invoke jareth.hugBack()


You could get lucky, of course, and have one thread complete the entire hug without the other one starting. If
steps 2 and 3 happened to occur in the opposite order, jareth would complete both hug and hugBack
before cory needed the lock on jareth. But a future run of the same application might deadlock because of
a different choice of the thread scheduler. Several design changes would fix this problem. The simplest would
be to make hug and hugBack not synchronized but have both methods synchronize on a single object
shared by all Friendly objects. This technique would mean that only one hug could happen at a time in all
the threads of a single application, but it would eliminate the possibility of deadlock. Other, more complicated
techniques would enable multiple simultaneous hugs without deadlock.


You are responsible for avoiding deadlock. The runtime system neither detects nor prevents deadlocks. It can
be frustrating to debug deadlock problems, so you should solve them by avoiding the possibility in your
design. One common technique is to use resource ordering. With resource ordering you assign an order on all
objects whose locks must be acquired and make sure that you always acquire locks in that order. This makes it
impossible for two threads to hold one lock each and be trying to acquire the lock held by the otherthey must
both request the locks in the same order, and so once one thread has the first lock, the second thread will block
trying to acquire that lock, and then the first thread can safely acquire the second lock.


Exercise 14.8: Experiment with the Friendly program. How often does the deadlock actually happen on
your system? If you add yield calls, can you change the likelihood of deadlock? If you can, try this exercise
on more than one kind of system. Remove the deadlock potential without getting rid of the synchronization.


14.8. Ending Thread Execution


A thread that has been started becomes alive and the isAlive method will return TRue for that thread. A
thread continues to be alive until it terminates, which can occur in one of three ways:



  • The run method returns normally.

  • The run method completes abruptly.

  • The application terminates.


Having run return is the normal way for a thread to terminate. Every thread performs a task and when that
task is over the thread should go away. If something goes wrong, however, and an exception occurs that is not
caught, then that will also terminate the threadwe look at this further in Section 14.12 on page 379. By the
time a thread terminates it will not hold any locks, because all synchronized code must have been exited by
the time run has completed.


A thread can also be terminated when its application terminates, which you'll learn about in "Ending
Application Execution" on page 369.


14.8.1. Cancelling a Thread


There are often occasions when you create a thread to perform some work and then need to cancel that work
before it is completethe most obvious example being a user clicking a cancel button in a user interface. To

Free download pdf