comparison src/org/eclipse/jetty/util/thread/Timeout.java @ 941:c948f674a2d5

simplify Timeout
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 11 Oct 2016 00:34:19 -0600
parents 8e9db0bbf4f9
children c157a786ed0b
comparison
equal deleted inserted replaced
940:b77d631b9e28 941:c948f674a2d5
31 * The nested class Task should be extended by users of this class to obtain call back notification of 31 * The nested class Task should be extended by users of this class to obtain call back notification of
32 * expires. 32 * expires.
33 */ 33 */
34 public class Timeout 34 public class Timeout
35 { 35 {
36 private static final Logger LOG = LoggerFactory.getLogger(Timeout.class); 36 private static final Logger LOG = LoggerFactory.getLogger(Timeout.class);
37 private Object _lock; 37 private Object _lock;
38 private long _duration; 38 private long _duration;
39 private volatile long _now=System.currentTimeMillis(); 39 private volatile long _now=System.currentTimeMillis();
40 private Task _head=new Task(); 40 private Task _head=new Task();
41 41
42 /* ------------------------------------------------------------ */ 42 /* ------------------------------------------------------------ */
43 public Timeout() 43 public Timeout(Object lock)
44 { 44 {
45 _lock=new Object(); 45 _lock=lock;
46 _head._timeout=this; 46 _head._timeout=this;
47 } 47 }
48 48
49 /* ------------------------------------------------------------ */ 49 /* ------------------------------------------------------------ */
50 public Timeout(Object lock) 50 /**
51 { 51 * @return Returns the duration.
52 _lock=lock; 52 */
53 _head._timeout=this; 53 public long getDuration()
54 } 54 {
55 return _duration;
56 }
55 57
56 /* ------------------------------------------------------------ */ 58 /* ------------------------------------------------------------ */
57 /** 59 /**
58 * @return Returns the duration. 60 * @param duration The duration to set.
59 */ 61 */
60 public long getDuration() 62 public void setDuration(long duration)
61 { 63 {
62 return _duration; 64 _duration = duration;
63 } 65 }
64 66
65 /* ------------------------------------------------------------ */ 67 /* ------------------------------------------------------------ */
66 /** 68 public long setNow()
67 * @param duration The duration to set. 69 {
68 */ 70 return _now=System.currentTimeMillis();
69 public void setDuration(long duration) 71 }
70 { 72
71 _duration = duration; 73 /* ------------------------------------------------------------ */
72 } 74 public long getNow()
75 {
76 return _now;
77 }
73 78
74 /* ------------------------------------------------------------ */ 79 /* ------------------------------------------------------------ */
75 public long setNow() 80 public void setNow(long now)
76 { 81 {
77 return _now=System.currentTimeMillis(); 82 _now=now;
78 } 83 }
79
80 /* ------------------------------------------------------------ */
81 public long getNow()
82 {
83 return _now;
84 }
85 84
86 /* ------------------------------------------------------------ */ 85 /* ------------------------------------------------------------ */
87 public void setNow(long now) 86 /** Get an expired tasks.
88 { 87 * This is called instead of {@link #tick()} to obtain the next
89 _now=now; 88 * expired Task, but without calling it's {@link Task#expire()} or
90 } 89 * {@link Task#expired()} methods.
90 *
91 * @return the next expired task or null.
92 */
91 93
92 /* ------------------------------------------------------------ */ 94 public Task expired()
93 /** Get an expired tasks. 95 {
94 * This is called instead of {@link #tick()} to obtain the next 96 synchronized (_lock)
95 * expired Task, but without calling it's {@link Task#expire()} or 97 {
96 * {@link Task#expired()} methods. 98 long _expiry = _now-_duration;
97 * 99 if (_head._next!=_head)
98 * @return the next expired task or null. 100 {
99 */ 101 Task task = _head._next;
100 public Task expired() 102 if (task._timestamp>_expiry)
101 { 103 return null;
102 synchronized (_lock)
103 {
104 long _expiry = _now-_duration;
105 104
106 if (_head._next!=_head) 105 task.unlink();
107 { 106 task._expired=true;
108 Task task = _head._next; 107 return task;
109 if (task._timestamp>_expiry) 108 }
110 return null; 109 return null;
110 }
111 }
111 112
112 task.unlink(); 113 public void cancelAll()
113 task._expired=true; 114 {
114 return task; 115 synchronized (_lock)
115 } 116 {
116 return null; 117 _head._next=_head._prev=_head;
117 } 118 }
118 } 119 }
119 120
120 /* ------------------------------------------------------------ */ 121 public long getTimeToNext()
121 public void tick() 122 {
122 { 123 synchronized (_lock)
123 final long expiry = _now-_duration; 124 {
125 if (_head._next==_head)
126 return -1;
127 long to_next = _duration+_head._next._timestamp-_now;
128 return to_next<0?0:to_next;
129 }
130 }
124 131
125 Task task=null; 132 @Override
126 while (true) 133 public String toString()
127 { 134 {
128 try 135 StringBuffer buf = new StringBuffer();
129 { 136 buf.append(super.toString());
130 synchronized (_lock) 137
131 { 138 Task task = _head._next;
132 task= _head._next; 139 while (task!=_head)
133 if (task==_head || task._timestamp>expiry) 140 {
134 break; 141 buf.append("-->");
135 task.unlink(); 142 buf.append(task);
136 task._expired=true; 143 task=task._next;
137 task.expire(); 144 }
138 } 145
139 146 return buf.toString();
140 task.expired(); 147 }
141 }
142 catch(Throwable th)
143 {
144 LOG.warn("EXCEPTION",th);
145 }
146 }
147 }
148 148
149 /* ------------------------------------------------------------ */ 149 /* ------------------------------------------------------------ */
150 public void tick(long now) 150 /* ------------------------------------------------------------ */
151 { 151 /* ------------------------------------------------------------ */
152 _now=now; 152 /* ------------------------------------------------------------ */
153 tick(); 153 /** Task.
154 } 154 * The base class for scheduled timeouts. This class should be
155 * extended to implement the expire() method, which is called if the
156 * timeout expires.
157 *
158 *
159 *
160 */
161 public static class Task
162 {
163 Task _next;
164 Task _prev;
165 Timeout _timeout;
166 long _timestamp=0;
167 boolean _expired=false;
155 168
156 /* ------------------------------------------------------------ */ 169 protected Task()
157 public void schedule(Task task) 170 {
158 { 171 _next=_prev=this;
159 schedule(task,0L); 172 }
160 }
161
162 /* ------------------------------------------------------------ */
163 /**
164 * @param task
165 * @param delay A delay in addition to the default duration of the timeout
166 */
167 public void schedule(Task task,long delay)
168 {
169 synchronized (_lock)
170 {
171 if (task._timestamp!=0)
172 {
173 task.unlink();
174 task._timestamp=0;
175 }
176 task._timeout=this;
177 task._expired=false;
178 task._delay=delay;
179 task._timestamp = _now+delay;
180 173
181 Task last=_head._prev; 174 private void unlink()
182 while (last!=_head) 175 {
183 { 176 _next._prev=_prev;
184 if (last._timestamp <= task._timestamp) 177 _prev._next=_next;
185 break; 178 _next=_prev=this;
186 last=last._prev; 179 _expired=false;
187 } 180 }
188 last.link(task); 181 }
189 }
190 }
191
192
193 /* ------------------------------------------------------------ */
194 public void cancelAll()
195 {
196 synchronized (_lock)
197 {
198 _head._next=_head._prev=_head;
199 }
200 }
201
202 /* ------------------------------------------------------------ */
203 public boolean isEmpty()
204 {
205 synchronized (_lock)
206 {
207 return _head._next==_head;
208 }
209 }
210
211 /* ------------------------------------------------------------ */
212 public long getTimeToNext()
213 {
214 synchronized (_lock)
215 {
216 if (_head._next==_head)
217 return -1;
218 long to_next = _duration+_head._next._timestamp-_now;
219 return to_next<0?0:to_next;
220 }
221 }
222
223 /* ------------------------------------------------------------ */
224 @Override
225 public String toString()
226 {
227 StringBuffer buf = new StringBuffer();
228 buf.append(super.toString());
229
230 Task task = _head._next;
231 while (task!=_head)
232 {
233 buf.append("-->");
234 buf.append(task);
235 task=task._next;
236 }
237
238 return buf.toString();
239 }
240
241 /* ------------------------------------------------------------ */
242 /* ------------------------------------------------------------ */
243 /* ------------------------------------------------------------ */
244 /* ------------------------------------------------------------ */
245 /** Task.
246 * The base class for scheduled timeouts. This class should be
247 * extended to implement the expire() method, which is called if the
248 * timeout expires.
249 *
250 *
251 *
252 */
253 public static class Task
254 {
255 Task _next;
256 Task _prev;
257 Timeout _timeout;
258 long _delay;
259 long _timestamp=0;
260 boolean _expired=false;
261
262 /* ------------------------------------------------------------ */
263 protected Task()
264 {
265 _next=_prev=this;
266 }
267
268 /* ------------------------------------------------------------ */
269 public long getTimestamp()
270 {
271 return _timestamp;
272 }
273
274 /* ------------------------------------------------------------ */
275 public long getAge()
276 {
277 final Timeout t = _timeout;
278 if (t!=null)
279 {
280 final long now=t._now;
281 if (now!=0 && _timestamp!=0)
282 return now-_timestamp;
283 }
284 return 0;
285 }
286
287 /* ------------------------------------------------------------ */
288 private void unlink()
289 {
290 _next._prev=_prev;
291 _prev._next=_next;
292 _next=_prev=this;
293 _expired=false;
294 }
295
296 /* ------------------------------------------------------------ */
297 private void link(Task task)
298 {
299 Task next_next = _next;
300 _next._prev=task;
301 _next=task;
302 _next._next=next_next;
303 _next._prev=this;
304 }
305
306 /* ------------------------------------------------------------ */
307 /** Schedule the task on the given timeout.
308 * The task exiry will be called after the timeout duration.
309 * @param timer
310 */
311 public void schedule(Timeout timer)
312 {
313 timer.schedule(this);
314 }
315
316 /* ------------------------------------------------------------ */
317 /** Schedule the task on the given timeout.
318 * The task exiry will be called after the timeout duration.
319 * @param timer
320 */
321 public void schedule(Timeout timer, long delay)
322 {
323 timer.schedule(this,delay);
324 }
325
326 /* ------------------------------------------------------------ */
327 /** Reschedule the task on the current timeout.
328 * The task timeout is rescheduled as if it had been cancelled and
329 * scheduled on the current timeout.
330 */
331 public void reschedule()
332 {
333 Timeout timeout = _timeout;
334 if (timeout!=null)
335 timeout.schedule(this,_delay);
336 }
337
338 /* ------------------------------------------------------------ */
339 /** Cancel the task.
340 * Remove the task from the timeout.
341 */
342 public void cancel()
343 {
344 Timeout timeout = _timeout;
345 if (timeout!=null)
346 {
347 synchronized (timeout._lock)
348 {
349 unlink();
350 _timestamp=0;
351 }
352 }
353 }
354
355 /* ------------------------------------------------------------ */
356 public boolean isExpired() { return _expired; }
357
358 /* ------------------------------------------------------------ */
359 public boolean isScheduled() { return _next!=this; }
360
361 /* ------------------------------------------------------------ */
362 /** Expire task.
363 * This method is called when the timeout expires. It is called
364 * in the scope of the synchronize block (on this) that sets
365 * the {@link #isExpired()} state to true.
366 * @see #expired() For an unsynchronized callback.
367 */
368 protected void expire(){}
369
370 /* ------------------------------------------------------------ */
371 /** Expire task.
372 * This method is called when the timeout expires. It is called
373 * outside of any synchronization scope and may be delayed.
374 *
375 */
376 public void expired(){}
377
378 }
379 182
380 } 183 }