JDK-4145910 : Thread.join() completes too early
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.1.5,1.1.6,1.2.0,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS:
    generic,solaris_2.4,solaris_8,windows_nt generic,solaris_2.4,solaris_8,windows_nt
  • CPU: generic,x86,sparc
  • Submitted: 1998-06-04
  • Updated: 2000-08-31
  • Resolved: 2000-08-31
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description

Name: el35337			Date: 06/04/98


//
// Thread.join() completes too early.
//
// The documentation for Thread.join() states:
//    "Waits for this thread to die."
//
// "thread died" should imply that the instruction pointer associated with the
// thread never changes again. However, Thread.join() does not implement these semantics.
//
// A thread which has been stopped may not die immediately because a finally clause on its
// stack may be blocked or otherwise delayed for legitimate reasons. However, Thread.join()
// returns immediately for such threads even if the instruction pointer for the thread will change
// subsequently (i.e. more code is executed).
//
// It seems reasonable that Thread.join() should not complete until the thread is truly dead
// as opposed to "almost dead" otherwise the caller cannot make any strong assertions about 
// what other concurrent activity may be in progress.
//
// To compile: javac Bug2.java
// To execute: java -classpath .;%CLASSPATH% Bug2
//


public class Bug2
{
   static public class SomeRunnable implements Runnable
   {
      public void run()
      {
         try {
            System.err.println("run() sleep(5000) begins in " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.err.println("run() exits in " + Thread.currentThread().getName());
         } catch (InterruptedException e) {
         } finally {
            try {
               Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.err.println("run() finally clause exits in " + Thread.currentThread().getName());
         }

      }
   }


   public static void main(String args[])
   {
         Thread  t1;

         try {

            t1 = new Thread(new SomeRunnable(), "t1");
            t1.start();
            Thread.sleep(2000);
            t1.stop();
            t1.join();
            System.err.println("t1.join completes");
         } catch (InterruptedException i) {
         }
   }
}
(Review ID: 32952)
======================================================================

Comments
EVALUATION This is clearly a violation of the contract of Thread.join, albeit one that involves the use of a deprecated API. joshua.bloch@Eng 1998-06-24 The reason the "join" happens to soon is because stop0 has incorreclty set the stillborn flag on a running thread. There are two fields of interest - both in thread.java a) stillborn This is set "true" to indicated that the thread was asked to stop before it was run. It is also set "true" to ensure one never restarts a thread which has exited. It's initialized "false" and subsequently set "true" in three places: 1. The jni_DetachCurrentThread routine. 2. The Thread.stop0 method ( called by the Thread.stop method ). 3. The ThreadRT0 routine (after the thread has executed it's "run" method). It is never reset to "false" b) PrivateInfo This field is set to the tid in threadCreate and threadBootstrap. The field is reset to zero in sysThreadExit and/or sysThreadFree. The join completes when the target thread is no longer alive, which is when both PrivateInfo != O AND stillborn == 0. Currently stop0 sets stillborn only when PrivateInfo is set ( i.e. when the thread is runnning). This is the wrong way around. The fix is to change this logic so that stop0 only sets stillborn when PrivateInfo is zero. timothy.preece@eng 1998-10-05 Bug verified as fixed via regression testing. john.s.lee@Eng 1999-01-21 -------------------------------------------------------------------- This has been fixed in HotSpot by changing the definition of isAlive() to depend only on the existence of an OS-level thread for the Java thread. See also bug 4314342. kenneth.russell@eng 2000-08-31
31-08-2000

SUGGESTED FIX The following change should fix the problem. 127a128,134 > * 4145910: > * The stop method will now set the stillborn flag ONLY when the thread is > * NOT running. This covers the case when a thread has been stopped before > * it has been started. Because stillborn is not set for a running thread > * the isALive method will return true until the thread has finally completed. > * The stillborn flag indicates that a thread has completed and will not > * run again. 141,143c148,149 < if (tid->PrivateInfo && !tid->stillborn) { < tid->stillborn = 1; < (void) threadPostException(p, exc); --- > if (tid->PrivateInfo == 0) { > tid->stillborn = 1; 144a151,153 > else if (!tid->stillborn) { > (void) threadPostException(p, exc); > } timothy.preece@eng 1998-10-05
05-10-1998