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();
}
}
P4P at Pando
I posted a write up today on Pandoblog.com about P4P. Check it out: P4P Behind the Scenes, Part 1. The other part is coming soon.
Xcode and environment.plist
I just spent a few frustrating hours trying to get the Pando client building on my Mac, under Xcode.
Apparently, if you start Xcode via Spotlight your ~/.MacOSX/environment.plist file isn't read. No doubt, something to do with how processes are launched via Spotlight. (Or rather, who launches them.) I didn't dig any deeper because I've got some work to do. :)
In terms of day-to-day work, this is something I never have to do -- I'm a server-side developer and all our server code is in Java and the client is written in C++. So, I moved Xcode to the dock!