Exercise 1.4: Resolving the thread bottleneck
Before you begin, you must complete Exercise 1.3:
Identifying a thread bottleneck.
To locate the deadlock in your code, you can use the the UML2 Sequence Diagram (the Object Interactions and Thread Interactions views) and the Call Stack profiling resource in the Profiling Monitor, in addition to the Thread View.
To resolve this deadlock, let's first find out which method calls and which objects are involved in the problem:
- In the Thread View, find the first philo* thread that enters a "Waiting for Lock" state. Pause your cursor over the "Waiting for Lock" segment. The tool tip identifies the lock that the thread is waiting for: Fork.<id number>.
- Right-click the Profiling resource for the run, and select Open With > UML2 Object Interactions. The UML2 Sequence Diagram view opens, displaying Object
Interactions.
- In the sequence diagram, scroll the view to find Fork.<id number>, and double-click to select it.
- Scroll down to find a horizontal arrow from one of the philo* threads to Fork.<id number>. These arrows show interactions between objects, and the first interaction between these two objects will indicate that the philo* thread has acquired Fork.<id number>. You'll find such an arrow labeled getName.
- Double-click getName. In the Thread View, the vertical Current Time indicator moves to show to see what was happening in the entire program when getName was called. You can see that the request was successful, as the philo* thread that is making the request does not enter the "Waiting for Lock" state.
- In the sequence diagram, double-click Fork.<id number> again, and scroll down to find a getName request that originated in a different philo* thread.
- Double-click this instance of getName. The Current Time indicator will show that the philo* thread making the request does not get Fork.<id number>, and enters a "Waiting for Lock" state.
In this instance, a request for a Fork that is held by another thread is the problem. Check other threads that end in the "Waiting for Lock" state to verify that this is true in other instances as well.
Now let's try to find the method that is causing the problem:
- Right-click the Profiling resource for the run, and select Open With > UML2 Thread Interactions. The UML2 Sequence Diagram view opens, displaying Thread
Interactions.
- In the Profiling Monitor, expand your Profiling resource, then
the Thread Analysis entry and the Call Stack entry.
- In the Thread View, where the names of threads are displayed, double-click the first of the philo* threads that enters the "Waiting for Lock" state. Notice that the Thread Interactions view changes to display information for only that thread.
- Scroll down to the end of the information for the thread, and double click the last method that the thread ran: the run method. The Call Stack in the Profiling Monitor displays all the calls on the stack at that time.
- In the Call Stack, note that the thread that is holding the lock has called the Sleep method in Philosopher.java; or that it is also waiting for a lock and consequently doing nothing.
- Check the other threads that end the run waiting for a lock; the Sleep method in Philosopher.java is often in the Call Stack, and may be the problem.
We now suspect the Sleep method. Let's have a look at the code:
- In the Call Stack, right-click an instance of Sleep(int) void [Philosopher.java] and select Open source. The source opens in the editor, at the location of the Sleep class.
- Examine the code. Note that the Sleep method is called from within the run method. There is first a call to trace, which prints out the message "got left...", and then a call to Sleep. By commenting out the call to Sleep, we can possibly prevent the deadlock.
- Comment out Sleep.
- Select File > Save.
Now profile your program again.
This time it runs without a deadlock, and writes to the console:
HeadWaiter reports all philosophers have finished dining normally
As you can see, the Thread View and the other views show you what happens to the threads as your program runs. It's up to you to perform the analysis and resolve the deadlock, based on your knowledge of your program.
Finish your tutorial by reviewing the materials in the Summary.