Thread interruption strangeness under Apple's Java6
I came across some odd thread behavior under Apple's Java6 on Leopard. I know it's still in "developer preview" state, but at Pando, we rely on Java6 -- under Linux, NIO performance is much better than Java5 -- and I develop on Mac. :) In the end, SoyLatte came to my rescue (which I recently stopped using because it was causing problems with Eclipse). Read on to see how and why...
The issue and the rescue
To start, here's a chunk of code that's core to the issue:
public static void main( String[] args ) throws Exception {
Thread t = new Thread(
new Runnable() {
public void run() {
while ( !Thread.currentThread().isInterrupted() )
; // doing something interesting
}
}
);
t.start();
Thread.sleep( 5000 ); // sleep on main thread
t.interrupt();
t.join();
}
Basically, I'm creating a new thread with a do-nothing task (Runnable) inside. The task loops forever as long as its owning thread hasn't been interrupted. This is a pretty standard idiom for tasks that don't invoke any methods that throw InterruptedException(s). After I start the thread and sleep for five seconds, I try to interrupt the thread then join it. (Remember that join()'ing a thread will cause the calling thread (the main() method in this case) to block until the joined thread terminates.) The expected behavior after t.join() is that main() terminates. Under Apple's Java6 that ain't the case!
I tested with build 1.6.0_04-dp-b06-110 of Apple's Java6 (the latest). Even if I change Thread.currentThread().isInterrupted() to Thread.interrupted() (which is not a good idea, normally) it still won't terminate.
Now, under build 1.5.0_13-b05-237 of Apple's Java5, the thread terminates as expected. Just for grins I tested on a few other OSes and they exhibited the correct behavior. Here's a breakdown of the versions I tried.
Correct behavior on
- Windows XP: build 1.6.0_01-b06 (Sun JVM)
- Linux: build 1.6.0_02-b05 (Sun JVM)
- OS X: build 1.5.0_13-b05-237 (Apple's Java5)
- OS X: build 1.6.0_03-p3-landonf_03_feb_2008_02_12-b00 (SoyLatte)
Wait! I said SoyLatte came to the rescue didn't I?! Well, if you use the client-mode VM then SoyLatte does work. By client-mode I mean starting Java like:
java -client ...
You get the server-mode VM by default. Unfortunately Apple's Java6 is still broken even in client-mode. Ugh Apple! Please release a real Java6 or let Sun do it!
A full test case
If you want to see the problem for yourself just compile and run the following test case.
public class ThreadTest {
public static void main( String[] args ) throws Exception {
Runnable r = null;
if ( args.length == 0 || "isInterrupted".equals( args[0] ) ) {
r = new Runnable() {
public void run() {
System.out.println( "-- Thread using Thread.currentThread().isInterrupted()" );
while ( !Thread.currentThread().isInterrupted() )
;
System.out.println( "-- Thread is done." );
}
};
}
else if ( "interrupted".equals( args[0] ) ) {
r = new Runnable() {
public void run() {
System.out.println( "-- Thread using Thread.interrupted()" );
while ( !Thread.interrupted() )
;
System.out.println( "-- Thread is done." );
}
};
}
else {
System.out.println( "Usage: ThreadTest [isInterrupted|interrupted]" );
return;
}
Thread t = new Thread( r );
System.out.println( "Starting thread." );
t.start();
Thread.sleep( 5000 );
System.out.println( "Interrupting thread." );
t.interrupt();
System.out.println( "Joining thread." );
t.join();
}
}