summaryrefslogtreecommitdiff
path: root/java/src/TimedWait.java
blob: acf771dfca1f8ead7ca1daafa2392bf77dbb6479 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*************************************************
 *
 * = PACKAGE
 *    JACE.ASX
 *
 * = FILENAME
 *    TimedWait.java
 *
 *@author Prashant Jain and Doug Schmidt
 *
 *************************************************/
package JACE.ASX;

public abstract class TimedWait
{
  /**
   * Default Constructor. Sets "this" to be used for the delegation of
   * the wait() call to. 
   */
  public TimedWait ()
  {
    object_ = this;
  }

  /**
   * Constructor. Allows subclasses to supply us with an Object that
   * is delegated the wait() call.
   *@param obj The Object that is delegated the wait() call.
   */
  public TimedWait (Object obj)
  {
    object_ = obj;
  }

  /**
   * Hook method that needs to be implemented by subclasses.
   */
  public abstract boolean condition ();

  /**
   * Wait until condition becomes true. Note that the method
   * blocks. Also note that this method is final to ensure that no one
   * overrides it. 
   * IMPORTANT: This method assumes it is called with the object_'s
   * monitor lock already held.
   */
  public final void timedWait () throws InterruptedException
  {
    // Acquire the monitor lock.
    if (!condition ()) 
      {
	// Only attempt to perform the wait if the condition isn't
	// true initially.
	for (;;) 
	  {
	    // Wait until we are notified.
	    object_.wait ();

	  // Recheck the condition.
	  if (condition ()) 
	    break; // Condition became true.
	  // else we were falsely notified so go back into wait
	  }
      }
  }

  /**
   * Template Method that implements the actual timed wait. Note that
   * this method is final to ensure that no one overrides it. 
   * IMPORTANT: This method assumes it is called with the object_'s
   * monitor lock already held.
   *@param tv Amount of time to do wait for.
   */
  public final void timedWait (TimeValue tv)
    throws InterruptedException,
           TimeoutException 
  {
    // Acquire the monitor lock.
    if (!condition ()) 
      {
	// Only attempt to perform the timed wait if the condition isn't
	// true initially.
	long start = System.currentTimeMillis ();
	long waitTime = tv.getMilliTime ();

	for (;;) {
	  // Wait until we are notified.
	  object_.wait (waitTime);

	  // Recheck the condition.
	  if (!condition ()) {
	    long now = System.currentTimeMillis ();
	    long timeSoFar = now - start;

	    // Timed out!
	    if (timeSoFar >= tv.getMilliTime ()) 
	      throw new TimeoutException ();
	    else 
	      // We still have some time left to wait, so adjust the
	      // wait_time.
	      waitTime = tv.getMilliTime () - timeSoFar; 
	  }
	  else
	    break;  // Condition became true.
	}
      }
  }

  /**
   * Notify any one thread waiting on the object_.  
   * IMPORTANT: This method assumes it is called with the object_'s
   * monitor lock already held.
   */
  public final void signal () {
    object_.notify ();
  }

  /**
   * Notify all threads waiting on the object_.  
   * IMPORTANT: This method assumes it is called with the object_'s
   * monitor lock already held.
   */
  public final void broadcast () {
    object_.notifyAll ();
  }

  /** 
   * The object we delegate to. If a subclass gives us a particular
   * object,  we use that to delegate to, otherwise, we ``delegate''
   * to ourself (i.e., this).
   */
  protected Object object_;

}