Overview

Chapter 8 - Inter-thread Communication

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Using join() to Wait for a Thread to Die
The join() method of Thread can be used to cause the current thread to block waiting for the specified thread to die. This is a relatively crude form of inter-thread communication, but on occasion it can be useful. If threadX runs the code
try {
    threadY.join()
} catch (InterruptedException x) {
}
threadX will block waiting for threadY to die. If threadX is interrupted while inside join() , it will throw an InterruptedException . There are three versions of the join() method available in Thread , all of which are public : join() , join(long) , and join(long, int) . Additionally, none of these methods can be overridden in a subclass because they are all declared final .
join()
public final void join()
        throws InterruptedException
The join() method causes the current thread to block and wait an unlimited amount of time for this thread to die. The current thread will throw an InterruptedException if interrupted while waiting for the specified thread to die.
join(long)
public final synchronized void join(long msTimeout)
        throws InterruptedException,
               IllegalArgumentException      // RuntimeException
The join(long) method causes the current thread to block and wait up to msTimeout milliseconds for the specified thread to die. If msTimeout is , the current thread will never time out and will wait forever for the specified thread to die (just like join() ). If msTimeout is less than , an IllegalArgumentException is thrown. The current thread will throw an InterruptedException if interrupted while waiting for the specified thread to die.
join(long, int)
public final synchronized void join(long msTimeout, int nanoSec)
        throws InterruptedException,
               IllegalArgumentException      // RuntimeException
The join(long, int) method works just like join(long) (see above) with the exception that nanoseconds can be added to the timeout value. The argument nanoSec is added to msTimeout to determine the total amount of time that the thread will wait for the specified thread to die before returning. An IllegalArgumentException is thrown if msTimeout is less than or if nanoSec is less than or greater than 999999 . The current thread will throw an InterruptedException if interrupted while waiting for the specified thread to die.
JoinDemo
The class JoinDemo (see Listing 8.12) demonstrates how join() can be used to wait for threads to die. The main thread spawns three new threads and then waits for each of them to die. Each of the threads lives for a different amount of time.
Listing 8.12  JoinDemo.javaDemonstration of the Use of join()
1: public class JoinDemo extends Object {
2:     public static Thread launch(String name , long napTime) {
3:         final long sleepTime = napTime;
4:
5:         Runnable r = new Runnable() {
6:                 public void run() {
7:                     try {
8:                         print(in run() - entering);
9:                         Thread.sleep(sleepTime);
10:                     } catch (InterruptedException x) {
11:                         print(interrupted!);
12:                     } finally {
13:                         print(in run() - leaving);
14:                     }
15:                 }
16:             };
17:    
18:         Thread t = new Thread(r, name);
19:         t.start();
20:
21:         return t;
22:     }
23:
24:     private static void print(String msg) {
25:         String name = Thread.currentThread().getName();
26:         System.out.println(name + : + msg);
27:     }
28:
29:     public static void main(String[] args) {
30:         Thread[] t = new Thread[3];
31:
32:         t[0] = launch(threadA, 2000);
33:         t[1] = launch(threadB, 1000);
34:         t[2] = launch(threadC, 3000);
35:
36:         for (int i = 0; i < t.length; i++) {
37:             try {
38:                 String idxStr = t[ + i + ];
39:                 String name = [ + t[i].getName() + ];
40:
41:                 print(idxStr + .isAlive()= +
42:                         t[i].isAlive() + + name);
43:                 print(about to do: + idxStr +
44:                         .join() + name);
45:
46:                 long start = System.currentTimeMillis();
47:                 t[i].join(); // wait for the thread to die
48:                 long stop = System.currentTimeMillis();
49:
50:                 print(idxStr + .join() - took +
51:                         (stop - start) + ms + name);
52:             } catch (InterruptedException x) {
53:                 print(interrupted waiting on # + i);
54:             }
55:         }
56:     }
57: }
In the static method launch() (lines 222) of JoinDemo , a new Runnable instance r is created. Inside the run() method of r , the thread prints an announcement (line 8), sleeps for the specified delay (line 9), and prints another message just before leaving run() (line 13). A new Thread is constructed and started for r and is given the name passed into launch() (lines 1819). A reference to this new running Thread is returned to the caller (line 21).
In main() (lines 2956), a Thread[] named t is created to hold three references (line 30). The launch() method is called three times with different parameters and the references returned are stored into t (lines 3234):
  t[0] is named threadA and sleeps two seconds before dying.
  t[1] is named threadB and sleeps one seconds before dying.
  t[2] is named threadC and sleeps three seconds before dying.
All three threads are running concurrently. threadB finishes first, threadA finishes second, and threadC finishes last.
After launching all three threads, the main thread continues on into the for loop (lines 3655). In this loop, main prints out some diagnostic information for each of the launched threads and then invokes join() on each of them to wait for each to die (line 47). Without all the extra information gathering and printing, the for loop boils down to this:
for (int i = 0; i < t.length; i++) {
    try {
        t[i].join(); // wait for the thread to die
    } catch (InterruptedException x) {
    }
}
The main thread blocks for about two seconds waiting for threadA to die. Meanwhile, threadB has already died, so when the main thread invokes join() on threadB , join() returns right away. The main thread then proceeds to block for about one second waiting for threadC to die.
Listing 8.13 shows the output produced from a particular run of JoinDemo . Your output should match fairly closely. The only differences should be a little variation in the number of milliseconds that the main thread spends inside join() and perhaps a few lines of output swapped with each other.
Listing 8.13  Output from JoinDemo
1: main: t[0].isAlive()=true [threadA]
2: threadA: in run() - entering
3: threadB: in run() - entering
4: threadC: in run() - entering
5: main: about to do: t[0].join() [threadA]
6: threadB : in run() - leaving
7: threadA : in run() - leaving
8: main: t[0].join() - took 1920 ms [threadA]
9: main: t[1].isAlive()=false [threadB]
10: main: about to do: t[1].join() [threadB]
11: main: t[1].join() - took 0 ms [threadB]
12: main: t[2].isAlive()=true [threadC]
13: main: about to do: t[2].join() [threadC]
14: threadC : in run() - leaving
15: main: t[2].join() - took 990 ms [threadC]
The main thread finds threadA still alive (line 1), invokes join() on it (line 5), and waits 1920 milliseconds for it to die (line 8). Notice that threadB reported that it was leaving its run() method while the main thread was waiting on threadA (line 6). Therefore, the main thread finds threadB already dead (line 9) and when join() is invoked (line 10), the main thread returns right away (line 11). Next, the main thread finds threadC still alive (line 12), invokes join() on it (line 13), and waits 990 milliseconds for it to die (line 15).

Toc


Java Thread Programming
Java Thread Programming
ISBN: 0672315858
EAN: 2147483647
Year: 2005
Pages: 149
Authors: Paul Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net