Overview

Chapter 14 - Waiting for the Full Timeout

Java Thread Programming
Paul Hyde
  Copyright 1999 Sams Publishing

Determining If wait() Should Be Invoked Again
When wait() returns, it could be because the timeout was reached or because it was notified. In fact, in the EarlyReturn example there are four ways that a thread blocked on wait() becomes unblocked. They are listed in Table 14.1.
Table 14.1  What To Do After wait() Returns
State
Action
InterruptedException thrown
Pass on InterruptedException
Timed out
Return false right away
Notified, minimum is met
Return true right away
Notified, minimum not met
Calculate time remaining, wait again
The InterruptedException is obvious and should be allowed to propagate up to indicate that the wait() call was terminated earlyprobably because someone wants this thread to clean up and die as soon as possible. Other than that, wait() is declared to return void so there is no direct indication as to whether the thread timed out or was notified. If it was notified, its possible that the condition has not yet been met and more time is available to wait again. When the thread returns from wait() , two calculations need to be done: one to see if the condition has been met, and another to see how much more time remains before the timeout value has been reached. If the condition has not been met and there is some time remaining, the thread should wait again. For this second call to wait() , a revised (shorter) timeout value needs to be passed.
EarlyReturnFix , shown in Listing 14.2, is basically the same as EarlyReturn except with a new waitUntilAtLeast() method (lines 1542). It deals with all of the issues listed in Table 14.1.
Listing 14.2  EarlyReturnFix.javaWaiting for the Full Timeout
1: public class EarlyReturnFix extends Object {
2:     private volatile int value;
3:
4:     public EarlyReturnFix(int initialValue) {
5:         value = initialValue;
6:     }
7:
8:     public synchronized void setValue(int newValue) {
9:         if (value != newValue) {
10:             value = newValue;
11:             notifyAll();
12:         }
13:     }
14:
15:     public synchronized boolean waitUntilAtLeast(
16:                 int minValue,
17:                 long msTimeout
18:            ) throws InterruptedException {
19:
20:         System.out.println(entering waitUntilAtLeast() - +
21:                 value= + value + ,minValue= + minValue);
22:
23:         long endTime = System.currentTimeMillis() + msTimeout;
24:         long msRemaining = msTimeout;
25:
26:         while ((value < minValue) && (msRemaining > 0L)) {
27:             System.out.println(in waitUntilAtLeast() - +
28:                     about to: wait(+ msRemaining +));
29:             wait(msRemaining);
30:             msRemaining = endTime - System.currentTimeMillis();
31:             System.out.println(in waitUntilAtLeast() - +
32:                     back from wait(), new msRemaining= +
33:                     msRemaining);
34:         }
35:
36:         System.out.println(leaving waitUntilAtLeast() - +
37:                 value= + value + ,minValue= + minValue);
38:
39:         // May have timed out, or may have met value,
40:         // calc return value.
41:         return (value >= minValue);
42:     }
43:
44:     public static void main(String[] args) {
45:         try {
46:             final EarlyReturnFix er = new EarlyReturnFix(0);
47:
48:             Runnable r = new Runnable() {
49:                     public void run() {
50:                         try {
51:                             Thread.sleep(1500);
52:                             er.setValue(2);
53:                             Thread.sleep(500);
54:                             er.setValue(3);
55:                             Thread.sleep(500);
56:                             er.setValue(4);
57:                         } catch (Exception x) {
58:                             x.printStackTrace();
59:                         }
60:                     }
61:                 };
62:
63:             Thread t = new Thread(r);
64:             t.start();
65:
66:             System.out.println(
67:                     about to: waitUntilAtLeast(5, 3000));
68:             long startTime = System.currentTimeMillis();
69:             boolean retVal = er.waitUntilAtLeast(5, 3000);
70:             long elapsedTime =
71:                     System.currentTimeMillis() - startTime;
72:
73:             System.out.println(after + elapsedTime +
74:                     ms, retVal= + retVal);
75:         } catch (InterruptedException ix) {
76:             ix.printStackTrace();
77:         }
78:     }
79: }
The waitUntilAtLeast() method declares that it might throw an InterruptedException (line 18) if one occurs while it is blocked waiting. This way, no action is assumed if the thread is interrupted , but the method passes on the exception to signal that it did not complete normally.
Inside waitUntilAtLeast() , the current time is added to the timeout value specified to determine endTime (line 23). This time limit will be used to determine if the thread should wait again. The number of milliseconds left before endTime is held in the local variable msRemaining . It is initially the full timeout value (line 24), but is recalculated each time wait() returns (line 30).
The while loop is entered only if the minimum value has not already been met and a positive timeout value was passed in (line 26). Inside the loop, after printing an informational message, the thread waits for the current msRemaining (line 29). Regardless of whether it returns from wait() because it was notified or because it timed out, a new msRemaining is calculated based on the difference between the time limit and the current system clock time (line 30).
After another informational message is printed, the while loop expression is re-evaluated (line 26). If the minimum value has been reached, the body of the while loop will not be re-executed. If the minimum value has still not been met, either the thread was notified early, or the wait() timed out. If the wait() timed out, msRemaining should be less than or equal to , and the body of the loop will not be re-executed. If it was early notification, the body of the loop will be re-executed.
  Caution It is important to be careful that is not accidentally passed to wait() . A timeout of indicates that the wait() should never time out . Line 26 in the EarlyReturnFix example checks that the new timeout value is greater than .
When the while is done (or if it was skipped altogether), an informational message is printed (lines 3637). The boolean value returned is calculated based on whether or not the minimum was reached (line 41). The waitUntilAtLeast() method can return for many reasons:
  A negative or zero timeout was specified.
  The waiting exceeded the limit specified by the timeout.
  The minimum had been met or exceeded before the method was invoked.
  The minimum was reached before the timeout.
Regardless of why waitUntilAtLeast() is returning, the return value is true if the minimum is currently met, and is false otherwise .
Listing 14.3 shows possible output from running EarlyReturnFix . Your output is likely to differ slightly on the exact millisecond figures.
Listing 14.3  Output from a Particular Run of EarlyReturnFix (with Line Numbers Added)
1: about to: waitUntilAtLeast(5, 3000)
2: entering waitUntilAtLeast() - value=0,minValue=5
3: in waitUntilAtLeast() - about to: wait(3000)
4: in waitUntilAtLeast() - back from wait(), new msRemaining=1570
5: in waitUntilAtLeast() - about to: wait(1570)
6: in waitUntilAtLeast() - back from wait(), new msRemaining=1080
7: in waitUntilAtLeast() - about to: wait(1080)
8: in waitUntilAtLeast() - back from wait(), new msRemaining=590
9: in waitUntilAtLeast() - about to: wait(590)
10: in waitUntilAtLeast() - back from wait(), new msRemaining=-20
11: leaving waitUntilAtLeast() - value=4,minValue=5
12: after 3020 ms, retVal=false
Each time through the loop and just before the wait() , the number of milliseconds passed to wait() is displayed (output lines 3, 5, 7, and 9). The main thread keeps calling setValue() with a new value, but it never gets up to 5 . Each time setValue() is called, the waiting thread is notified, returns from wait() , recalculates the number of milliseconds remaining, and determines if it should loop again. Finally, msRemaining is non-positive, and the loop breaks (line 10). The minimum has not been met in 3020 milliseconds, so false is returned (line 12).
The next section shows a more complete example that allows a timeout value of to be passed in and removes all the clutter of the main() method.

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