Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Your Email:

Eye on performance: Wait leaks

By Jack Shirazi & Kirk Pepperdine
2005-04-28


Simulating a Wait Leak

The best way to learn how to spot wait leaks is to see one and understand what caused it. Listing 1 demonstrates a very simple wait leak. The WaitLeak class implements Runnable, and each thread sits and waits until it gets notified, then terminates. In our simulation, four WaitLeak threads are started, one every second. Another class, the WaitLeakNotifier, notifies all threads sitting in the WaitLeakwait() call, then terminates. The main method takes one parameter, the number of milliseconds to wait before the WaitLeakNotifier will notify all of the waiting threads.

Listing 1. Wait leak simulation classes

public class WaitLeak implements Runnable

{
private static Object LOCK = new Object();

public static void main(String[] args)
throws Exception
{
int WAITTIME = Integer.parseInt(args[0]);
int NUMTHREADS = 4;

(new Thread(new WaitLeakNotifier(WAITTIME))).start();
for (int i = 0; i < NUMTHREADS; i++)
{
Thread.sleep(1000);
(new Thread(new WaitLeak())).start();
}
}

public void run()
{
System.out.println("Starting thread " + Thread.currentThread());
synchronized(LOCK)
{
try{
LOCK.wait();
} catch(InterruptedException e) {}
}
System.out.println("Terminating thread " + Thread.currentThread());
}

}

class WaitLeakNotifier implements Runnable
{
long waittime;
public WaitLeakNotifier(long time)
{
waittime = time;
}

public void run()
{
long now = System.currentTimeMillis();
long diff = 0;
while( (diff = System.currentTimeMillis() - now) < waittime)
{
try {
Thread.sleep(waittime - diff);
} catch(InterruptedException e){}
}
synchronized(WaitLeak.LOCK)
{
WaitLeak.LOCK.notifyAll();
}
}
}
Engineering a race condition
Figure 1 shows three possible scenarios, run with different delays before the notification is sent.

The top pane shows our program with a relatively large delay, like 10 seconds, as shown below:

java WaitLeak 10000
This approach results in all four WaitLeak threads starting up, waiting, getting the notification after 10 seconds, and then terminating.

The second pane of Figure 1 shows our program with a delay halfway through WaitLeak startup, like 2 or 3 seconds:

java WaitLeak 2000
In this scenario, the WaitLeak threads that start earlier than the notifier thread get the notification and terminate, but the WaitLeak threads that start after the notification are sent will wait forever.

The third scenario has a very short delay time like 1 millisecond, shown below, and is illustrated in the third pane of Figure 1.

java WaitLeak 1
Figure 1. Wait leaks in action


In this case, the WaitLeakNotifier sends its notification before any threads have started. So no threads will get the notification from the WaitLeakNotifier, leaving all the threads blocked, forever, in the wait state.

Listing 2 shows a stack trace minutes after startup, taken from the second scenario. (You obtain stack traces by typing Ctrl+Break on Windows, or Ctrl+\ on Unix, or sending a kill -3 to the process on Unix.)
Listing 2. Thread stack dump for java WaitLeak 2000

"Thread-4" prio=5 tid=0x00a0eee8 nid=0xf04 in Object.wait() [2d1f000..2d1fd8c]

at java.lang.Object.wait(Native Method)
- waiting on <0x1002c780> (a java.lang.Object)
at java.lang.Object.wait(Unknown Source)
at WaitLeak.run(WaitLeak.java:25)
- locked <0x1002c780> (a java.lang.Object)
at java.lang.Thread.run(Unknown Source)

"Thread-3" prio=5 tid=0x00a0c418 nid=0xc5c in Object.wait() [2cdf000..2cdfd8c]
at java.lang.Object.wait(Native Method)
- waiting on <0x1002c780> (a java.lang.Object)
at java.lang.Object.wait(Unknown Source)
at WaitLeak.run(WaitLeak.java:25)
- locked <0x1002c780> (a java.lang.Object)
at java.lang.Thread.run(Unknown Source)

"Thread-2" prio=5 tid=0x00a0d7a0 nid=0x118c in Object.wait() [2c9f000..2c9fd8c]
at java.lang.Object.wait(Native Method)
- waiting on <0x1002c780> (a java.lang.Object)
at java.lang.Object.wait(Unknown Source)
at WaitLeak.run(WaitLeak.java:25)
- locked <0x1002c780> (a java.lang.Object)
at java.lang.Thread.run(Unknown Source)


Tutorial Pages:
» Gain a Better Understanding of this Curious Race Condition
» Wait Leaks
» Simulating a Wait Leak
» Spotting a Wait Leak
» The Final Word
» Resources


First published by IBM developerWorks


 | Bookmark
Related Tutorials:
» All about JAXP, Part 1
» Make Database Queries Without the Database
» Load List Values for Improved Efficiency
» 2 Ways To Implement Session Tracking
» A Simple Way to Read an XML File in Java
» Develop Aspect-Oriented Java Applications with Eclipse and AJDT