|
||||
| Copyright 1999 Sams Publishing |
|
|
||
|
|
|
| A General-Purpose Wait-Until Pattern |
|
|
|
| In this section, Ill show you a more complete example that can be used as a model and expanded to fit your real-world needs when a wait-until scenario is needed. The main enhancement is to allow a timeout of to be passed in just as wait() allows. |
|
|
|
| On Object , a call to |
|
|
|
| public final void wait() throws InterruptedException |
|
|
|
| behaves as if was passed into |
|
|
|
| public final void wait(long timeout) throws InterruptedException |
|
|
|
|
in the sense that it waits until notified, regardless of how much real time elapses.
FullWait
, shown in Listing 14.4, expands upon
EarlyNotifyFix
to allow
msTimeout
to be
when invoking
waitUntilAtLeast()
to
|
|
|
|
| Listing 14.4 FullWait.javaA Good Base Design Pattern to Use for Wait-Until Situations |
|
|
|
| 1: public class FullWait extends Object { |
| 2: private volatile int value; |
| 3: |
| 4: public FullWait(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: if (msTimeout == 0L) { |
| 21: while (value < minValue) { |
| 22: wait(); // wait indefinitely until notified |
| 23: } |
| 24: |
| 25: // condition has finally been met |
| 26: return true; |
| 27: } |
| 28: |
| 29: // only wait for the specified amount of time |
| 30: long endTime = System.currentTimeMillis() + msTimeout; |
| 31: long msRemaining = msTimeout; |
| 32: |
| 33: while ((value < minValue) && (msRemaining > 0L)) { |
| 34: wait(msRemaining); |
| 35: msRemaining = endTime - System.currentTimeMillis(); |
| 36: } |
| 37: |
| 38: // May have timed out, or may have met value, |
| 39: // calc return value. |
| 40: return (value >= minValue); |
| 41: } |
| 42: |
| 43: public String toString() { |
| 44: return getClass().getName() + [value= + value + ]; |
| 45: } |
| 46: } |
|
|
|
| FullWait is based upon EarlyReturnFix with the main() method and the informational messages removed. The waitUntilAtLeast() method (lines 1541) has been expanded to support a timeout of . |
|
|
|
|
If
msTimeout
is equal to
(line 20), the
while
loop continues to
wait()
until the minimum value has been met (lines 2123). If the minimum was met before
waitUntilAtLeast()
was invoked, the
while
loops body is never executed, and
true
is returned. Otherwise, the body of the
while
loop is executed and the thread waits until notified (line 22). Every time
setValue()
is called with a new value, any and all waiting threads are notifiedregardless of what value was set. This means that the
wait()
(line 22) might be notified before the minimum is met. If this happens, the
while
loop will simply execute again,
|
|
|
|
|
If
msTimeout
is
|
|
|
|
|
FullWaitMain
in Listing 14.5 constructs a
FullWait
and
|
|
|
|
|
Listing 14.5 FullWaitMain.javaCode to
|
|
|
|
| 1: public class FullWaitMain extends Object { |
| 2: private FullWait fullwait; |
| 3: private Thread internalThread; |
| 4: private volatile boolean noStopRequested; |
| 5: |
| 6: public FullWaitMain(FullWait fw) { |
| 7: fullwait = fw; |
| 8: |
| 9: noStopRequested = true; |
| 10: Runnable r = new Runnable() { |
| 11: public void run() { |
| 12: try { |
| 13: runWork(); |
| 14: } catch (Exception x) { |
| 15: x.printStackTrace(); |
| 16: } |
| 17: } |
| 18: }; |
| 19: |
| 20: internalThread = new Thread(r); |
| 21: internalThread.start(); |
| 22: } |
| 23: |
| 24: private void runWork() { |
| 25: int count = 6; |
| 26: |
| 27: while (noStopRequested) { |
| 28: fullwait.setValue(count); |
| 29: System.out.println(just set value to + count); |
| 30: count++; |
| 31: |
| 32: try { |
| 33: Thread.sleep(1000); |
| 34: } catch (InterruptedException x) { |
| 35: // reassert interrupt |
| 36: Thread.currentThread().interrupt(); |
| 37: } |
| 38: } |
| 39: } |
| 40: |
| 41: public void stopRequest() { |
| 42: noStopRequested = false; |
| 43: internalThread.interrupt(); |
| 44: } |
| 45: |
| 46: public boolean isAlive() { |
| 47: return internalThread.isAlive(); |
| 48: } |
| 49: |
| 50: public static void waitfor(FullWait fw, int val, long limit) |
| 51: throws InterruptedException { |
| 52: |
| 53: System.out.println(about to waitUntilAtLeast(+ |
| 54: val + , + limit +) ...); |
| 55: |
| 56: long startTime = System.currentTimeMillis(); |
| 57: boolean retVal = fw.waitUntilAtLeast(val, limit); |
| 58: long endTime = System.currentTimeMillis(); |
| 59: |
| 60: System.out.println(waited for + |
| 61: (endTime - startTime) + |
| 62: ms, retVal= + retVal + \n---------------); |
| 63: } |
| 64: |
| 65: public static void main(String[] args) { |
| 66: try { |
| 67: FullWait fw = new FullWait(5); |
| 68: FullWaitMain fwm = new FullWaitMain(fw); |
| 69: |
| 70: Thread.sleep(500); |
| 71: |
| 72: // should return true before 10 seconds |
| 73: waitfor(fw, 10, 10000L); |
| 74: |
| 75: // should return true right away --already >= 6 |
| 76: waitfor(fw, 6, 5000L); |
| 77: |
| 78: // should return true right away |
| 79: // --already >= 6 (negative time ignored) |
| 80: waitfor(fw, 6, -1000L); |
| 81: |
| 82: // should return false right away --not there |
| 83: // yet & negative time |
| 84: waitfor(fw, 15, -1000L); |
| 85: |
| 86: // should return false after 5 seconds |
| 87: waitfor(fw, 999, 5000L); |
| 88: |
| 89: // should eventually return true |
| 90: waitfor(fw, 20, 0L); |
| 91: |
| 92: fwm.stopRequest(); |
| 93: } catch (InterruptedException x) { |
|
94: System.err.println(*unexpectedly*
|
| 95: somewhere in main()); |
| 96: } |
| 97: } |
| 98: } |
|
|
|
|
In
main()
, a
FullWait
object is
|
|
|
|
|
The constructor for
FullWaitMain
(lines 622) stores the reference to the
FullWait
object, starts the internal thread running, and then returns. The internal thread invokes
runWork()
(lines 2439). In the
while
loop inside
runWork()
, the thread invokes the
setValue()
method on the
FullWait
object (line 28). Initially, it
|
|
|
|
| Back in main() , several calls to the static method waitFor() are made. The waitFor() method (lines 5063) is used to call waitUntilAtLeast() on the FullWait object. Each time informational messages are printed, the time spent inside waitUntilAtLeast() is measured, and the return value is captured. |
|
|
|
|
The first
waitFor()
call (line 73) waits for up to 10 seconds for the value to reach
10
. The value should be at about
6
when this is called, and because it
|
|
|
|
|
The
|
|
|
|
| For cleanup purposes, stopRequest() is called (line 92) to shut down the internal thread. Most of main() is in a try / catch block (lines 6696) because an InterruptedException might be thrown. In this case, this occurrence is quite unexpected and a message to that effect is printed if it happens (lines 9495). |
|
|
|
| Listing 14.6 shows output from a particular run of FullWaitMain . Your times will probably vary from this a bit, but the true and false return values should match exactly for each of the scenarios. |
|
|
|
|
Listing 14.6 Sample Output from Running FullWaitMain (Your Output Will
|
|
|
|
| 1: just set value to 6 |
| 2: about to waitUntilAtLeast(10, 10000) ... |
| 3: just set value to 7 |
| 4: just set value to 8 |
| 5: just set value to 9 |
| 6: just set value to 10 |
| 7: waited for 3630 ms, retVal=true |
| 8: --------------- |
| 9: about to waitUntilAtLeast(6, 5000) ... |
| 10: waited for 0 ms, retVal=true |
| 11: --------------- |
| 12: about to waitUntilAtLeast(6, -1000) ... |
| 13: waited for 0 ms, retVal=true |
| 14: --------------- |
| 15: about to waitUntilAtLeast(15, -1000) ... |
| 16: waited for 0 ms, retVal=false |
| 17: --------------- |
| 18: about to waitUntilAtLeast(999, 5000) ... |
| 19: just set value to 11 |
| 20: just set value to 12 |
| 21: just set value to 13 |
| 22: just set value to 14 |
| 23: waited for 5000 ms, retVal=false |
| 24: --------------- |
| 25: about to waitUntilAtLeast(20, 0) ... |
| 26: just set value to 15 |
| 27: just set value to 16 |
| 28: just set value to 17 |
| 29: just set value to 18 |
| 30: just set value to 19 |
| 31: just set value to 20 |
| 32: waited for 5050 ms, retVal=true |
| 33: --------------- |
|
|
|
||
|
Toc |
|||