|
|
Normally, only threads in Monitors are used to manage access to code that should only be run by a single thread at a time. Monitors are covered in more detail in the next section. The other two common thread states you may see are R, runnable threads and CW, threads in a condition wait state. Runnable threads by definition are threads that could be running or are running at that instance of time. On a multi-processor machine running a true multi-processing Operating System it is possible for all the runnable threads to be running at one time. However its more likely for the other runnable threads to be waiting on the thread scheduler to have their turn to run.
Threads in a condition wait state can be thought of as waiting for an event
to occur. Often a thread will appear in state CW if it is in a "main" (TID:0xebc981e0, sys_thread_t:0x26bb0, state:CW) prio=5 at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:424) at HangingProgram.main(HangingProgram.java:33)The code that created this stack trace is as follows:
synchronized(t1) {
try {
t1.wait(); //line 33
}catch (InterruptedException e){}
}
In the Java 2 release monitor operations, including our wait here, are handled by the Java Virtual Machine through a JNI call to sysMonitor. The condition
wait thread is kept on a special monitor wait queue on the object it is waiting
on. This explains why even though you are only waiting on an object that the
code still needs to be synchronized on that object as it is infact using
the monitor for that object.
Examining MonitorsThis brings us to the other part of the stack trace: the monitor dump. If you consider that the threads section of a stack trace identifies the multithreaded part of your application, then the monitors section represents the parts of your application that are single threaded.It may be easier to imagine a monitor as a car wash. In most car washes, only one car can be in the wash at a time. In your Java code only one thread at a time can have the lock to a synchronized piece of code. All the other threads queue up to enter the synchronized code just as cars queue up to enter the car wash. A monitor can be thought of as a lock on an object, and every object has a monitor. When you generate a stack trace, monitors are either listed as being registered or not. In the majority of cases these registered monitors, or system monitors, should not be the cause of your software problems, but it helps to be able to understand and recognize them. The following table describes the common registered monitors:
The monitor registry itself is protected by a monitor. This
means the thread that owns the lock is the last thread to use a
monitor. It is very likely this thread is also the current
thread.
Because only one thread can enter a synchronized block at a time, other
threads queue up at the start of the synchronized code and appear as
thread state Any code waiting on an object or event (a wait method) also has to be inside a synchronized block. However, once the wait method is called, the lock on the synchronized object is given up. When the thread in the wait state is notified of an event to the object, it has to compete for exclusive access to that object, and it has to obtain the monitor. Even when a thread has sent a "notify event" to the waiting threads, none of the waiting threads can actually gain control of the monitor lock until the notifying thread has left its synchronized code block. You will see "Waiting to be notified" for threads at the wait method Putting the Steps Into PracticeExample 1
Consider a real-life problem such as Bug ID
4098756, for example.
You can find details on this bug in JDC Bug Parade.
This bug documents a problem that occurs when using a
When the user selects one of the choices from the Fortunately, this problem is reproducible and there was a Java stack trace to help track down the problem. The full stack trace is in the bug report page, but you only need to focus on the following two key threads:
"AWT-Windows" (TID:0xf54b70,
sys_thread_t:0x875a80,Win32ID:0x67,
state:MW) prio=5
java.awt.Choice.select(Choice.java:293)
sun.awt.windows.WChoicePeer.handleAction(
WChoicePeer.java:86)
"AWT-EventQueue-0" (TID:0xf54a98,sys_thread_t:0x875c20,
Win32ID:0x8f, state:R) prio=5
java.awt.Choice.remove(Choice.java:228)
java.awt.Choice.removeAll(Choice.java:246)
The
This indicates that the Example 2 In this second example you will investigate a bug that on initial outset appears to be a fault in Swing but as you will discover is due to the fact that Swing is not thread safe. Again the bug report is available to view on the JDC site, the bug number this time is 4098525.
Here is a cut down sample of the code used to reproduce this problem. The modal dialog is being created from within the
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import javax.swing.*;
class MyDialog extends Dialog
implements ActionListener {
MyDialog(Frame parent) {
super(parent, "My Dialog", true);
Button okButton = new Button("OK");
okButton.addActionListener(this);
add(okButton);
pack();
}
public void actionPerformed(ActionEvent event) {
dispose();
}
}
public class Tester extends JPanel {
MyDialog myDialog;
boolean firstTime = true;
public Tester (JFrame frame) throws Exception {
super();
myDialog = new MyDialog(frame);
}
void showDialogs() {
myDialog.show();
}
public void paint(Graphics g) {
super.paint(g);
if (firstTime) {
firstTime = false;
showDialogs();
}
}
public static void main(String args[])
throws Exception {
JFrame frame = new JFrame ("Test");
Tester gui = new Tester(frame);
frame.getContentPane().add(gui);
frame.setSize(800, 600);
frame.pack();
frame.setVisible(true);
}
}
When you run this program you find that it deadlocks straight away. By taking a stack trace you see the these key threads.
The stack trace you have here is slightly different to the stack trace that
appears in the bug report, but caused by the same effect. We are also
using the Java 2 release to generate the trace and supplied the option
"AWT-EventQueue-1" (
TID:0xebca8c20, sys_thread_t:0x376660,
state:MW) prio=6
at java.awt.Component.invalidate(Component.java:1664)
at java.awt.Container.invalidate(Container.java:507)
t java.awt.Window.dispatchEventImpl(Window.java:696)
at java.awt.Component.dispatchEvent(
Component.java:2289)
at java.awt.EventQueue.dispatchEvent(
EventQueue.java:258)
at java.awt.EventDispatchThread.run(
EventDispatchThread.java:68)
If you look for that line in file java/awt/Component.java which is contained in the src.jar archive, you see the following:
public void invalidate() {
synchronized (getTreeLock()) { //line 1664
This is where our application is stuck, it is waiting for the getTreeLock monitor lock to become free. The next task is to find out which thread has this getTreeLock monitor lock held.
To see who is holding this monitor lock you look at the Monitor cache dump and in this example you can see the following:
Monitor Cache Dump:
java.awt.Component$AWTTreeLock@EBC9C228/EBCF2408:
owner "AWT-EventQueue-0" ( 0x263850) 3 entries
Waiting to enter:
"AWT-EventQueue-1" (0x376660)
The method
static final Object LOCK = new AWTTreeLock();
static class AWTTreeLock {}
The current owner is AWT-EventQueue-0. Thie thread called our paint method to create our modal Dialog via a call to paintComponent. paintComponent itself was called from an update call of JFrame.
So where was the lock set? Well there is no simple way to find out which
stack frame actually held the lock but on a simple search of
at Tester.paint(Tester.java:39)
at javax.swing.JComponent.paintChildren(
JComponent.java:388)
The rest of the puzzle is pieced together by analyzing the MDialogPeer show method. The Dialog code creates a new ModalThread which is why
you see an AWT-Modal thread in the stack trace output, this
thread is used to post the Dialog. It is when this event is dispatched
using AWT-EventQueue-1 which used to be the AWT Dispatch proxy
that getTreeLock monitor access is required and so you have a deadlock.
Unfortunately Swing code is not designed to be thread safe and so the
workaround in this example is to not create modal dialogs inside a Swing
paint methods. Since Swing has to do alot of locking and calculations as
to which parts of a lightweight component needs to be painted it is strongly
advised to not include sychronized code or code that will result
in a synchronized call such as in a modal dialog, inside This completes Java stack traces theory, and you should now know what to look for the next time you see a stack trace. To save time, you should make full use of the JDC bug search to see if the problem you are having has already been reported by someone else. Expert's ChecklistTo summarize, these are the steps to take the next time you come across a problem in a Java program.
[TOP]
_______ |