Platforms AffectedThread Join Bug Demonstration
All Netscape VMs have this problem including Netscape 4.05.
Basically, the Thread.join() method blocks forever or the amount of milliseconds it was told to join for if it is passed a parameter. The Thread never actually succeeds in informing Thread.join() that the thread ended.
Note: Do not confuse this with the ThreadGroup security bug in Netscape 3.x VMs. This happens regardless of ThreadGroup.
Details On The Thread Join Bug
Thread.join() stops the current thread until the thread it has "joined" to is dead. This is useful if you want to start and stop threads in a particular order without the threads knowing about each other.
A more useful use of this method is a TIMEOUT mechanism for Communications programming. Network Sockets and URLConnections in Java BLOCK the current thread from processing while they are trying to communicate over the wire.
If your internet connection is slow, though, you will end up waiting forever. Thus, it is nice to be able to "timeout" and stop the processing of the socket if you feel it is taking too long.
Normally, the pattern would involve starting the communication processing in another thread, and then in the main thread, calling Thread's join() method. The following would be an example:
Thread t = new Thread(this); t.start(); t.join(5000); // Timeout after 5 seconds
Unfortunately, on Netscape VMs, regardless of how long it took for the thread to complete, it will ALWAYS wait the full five seconds. I first noticed this bug when I was writing a class library to allow Java to communicate with CGI scripts (JavaCGIBridge).
Let's take a look at the source code inside JavaSoft's java.lang.Thread class:
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
This routine looks OK, except notice that it relys on wait()ing for a notify() or notifyAll(). Presumably, when a Thread dies, a notify is issued to the joined thread letting it know that it can stop waiting.
Netscape's VM does not do this, and hence it blocks forever or until the wait() timeout.
The code demo at the bottom of this page demonstrates this bug by allowing you to set up how long the launched thread should run AND how long to set up the JOIN timeout.
Then, click on the start thread button. At this point, if the timeout is longer than the time to run the thread, the resulting length of the thread should be less than the timeout. Instead, it is the length of the timeout on Netscape.
The default time to run the thread is 2000 milliseconds and 3000 milliseconds to timeout. What you will find on non-Netscape VMs is that the time the thread actually ran will be a tiny bit above 2000 milliseconds. On Netscape VM's, it will always wait the full 3000 milliseconds.
Note, on these examples, the actual time the thread ran value is usually a tiny bit above what you expect. This is because there is java code inbetween when the thread stops and when the code picks up the end and begin time. This results in some discrepency, but the actual jist of the demonstration holds true.
Thread Join Bug Workaround
Simple. You need to write different timeout code. In the applet workaround example below, I replace the Thread.join() code with code that is similar to JavaSoft's Thread join source code.
But there are some twists.
References
Another Applet Demonstrating The Bug By Alvis at RogueWave. No workaround given. Panel coloring does not work on all browsers.
Concurrent Programming in Java: Design Principles and Patterns by Doug Lea. This book goes into using join() as a timeout pattern. Warning, this book is not an easy read -- it is quite technical. A better introduction is listed below.
Java Threads by Scott Oaks and Henry Wong is a good reference on how threads work for the layperson.
JavaSoft gives out the source code for their class libraries. I found out how Thread.join() was implmented by looking in the java/lang/Thread.java file.
Applet Demonstrating The Thread Join Bug
View The Source To ThreadJoinBug.java
Applet With Thread Join Bug Workaround
View The Source To ThreadJoinFix.java