001: /*
002: * Written by Doug Lea with assistance from members of JCP JSR-166
003: * Expert Group and released to the public domain, as explained at
004: * http://creativecommons.org/licenses/publicdomain
005: */
006:
007: package org.apache.beehive.netui.util.internal.concurrent;
008:
009: /**
010: * A <tt>TimeUnit</tt> represents time durations at a given unit of
011: * granularity and provides utility methods to convert across units,
012: * and to perform timing and delay operations in these units. A
013: * <tt>TimeUnit</tt> does not maintain time information, but only
014: * helps organize and use time representations that may be maintained
015: * separately across various contexts. A nanosecond is defined as one
016: * thousandth of a microsecond, a microsecond as one thousandth of a
017: * millisecond, a millisecond as one thousandth of a second, a minute
018: * as sixty seconds, an hour as sixty minutes, and a day as twenty four
019: * hours.
020: *
021: * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods
022: * how a given timing parameter should be interpreted. For example,
023: * the following code will timeout in 50 milliseconds if the {@link
024: * org.apache.beehive.netui.util.concurrent.locks.Lock lock} is not available:
025: *
026: * <pre> Lock lock = ...;
027: * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
028: * </pre>
029: * while this code will timeout in 50 seconds:
030: * <pre>
031: * Lock lock = ...;
032: * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ...
033: * </pre>
034: *
035: * Note however, that there is no guarantee that a particular timeout
036: * implementation will be able to notice the passage of time at the
037: * same granularity as the given <tt>TimeUnit</tt>.
038: *
039: * @since 1.5
040: * @author Doug Lea
041: */
042: abstract class TimeUnit implements java.io.Serializable {
043:
044: public static final TimeUnit NANOSECONDS = new TimeUnit(0,
045: "NANOSECONDS") {
046: public long toNanos(long d) {
047: return d;
048: }
049:
050: public long toMicros(long d) {
051: return d / (C1 / C0);
052: }
053:
054: public long toMillis(long d) {
055: return d / (C2 / C0);
056: }
057:
058: public long toSeconds(long d) {
059: return d / (C3 / C0);
060: }
061:
062: public long toMinutes(long d) {
063: return d / (C4 / C0);
064: }
065:
066: public long toHours(long d) {
067: return d / (C5 / C0);
068: }
069:
070: public long toDays(long d) {
071: return d / (C6 / C0);
072: }
073:
074: public long convert(long d, TimeUnit u) {
075: return u.toNanos(d);
076: }
077:
078: int excessNanos(long d, long m) {
079: return (int) (d - (m * C2));
080: }
081: };
082: public static final TimeUnit MICROSECONDS = new TimeUnit(1,
083: "MICROSECONDS") {
084: public long toNanos(long d) {
085: return x(d, C1 / C0, MAX / (C1 / C0));
086: }
087:
088: public long toMicros(long d) {
089: return d;
090: }
091:
092: public long toMillis(long d) {
093: return d / (C2 / C1);
094: }
095:
096: public long toSeconds(long d) {
097: return d / (C3 / C1);
098: }
099:
100: public long toMinutes(long d) {
101: return d / (C4 / C1);
102: }
103:
104: public long toHours(long d) {
105: return d / (C5 / C1);
106: }
107:
108: public long toDays(long d) {
109: return d / (C6 / C1);
110: }
111:
112: public long convert(long d, TimeUnit u) {
113: return u.toMicros(d);
114: }
115:
116: int excessNanos(long d, long m) {
117: return (int) ((d * C1) - (m * C2));
118: }
119: };
120: public static final TimeUnit MILLISECONDS = new TimeUnit(2,
121: "MILLISECONDS") {
122: public long toNanos(long d) {
123: return x(d, C2 / C0, MAX / (C2 / C0));
124: }
125:
126: public long toMicros(long d) {
127: return x(d, C2 / C1, MAX / (C2 / C1));
128: }
129:
130: public long toMillis(long d) {
131: return d;
132: }
133:
134: public long toSeconds(long d) {
135: return d / (C3 / C2);
136: }
137:
138: public long toMinutes(long d) {
139: return d / (C4 / C2);
140: }
141:
142: public long toHours(long d) {
143: return d / (C5 / C2);
144: }
145:
146: public long toDays(long d) {
147: return d / (C6 / C2);
148: }
149:
150: public long convert(long d, TimeUnit u) {
151: return u.toMillis(d);
152: }
153:
154: int excessNanos(long d, long m) {
155: return 0;
156: }
157: };
158: public static final TimeUnit SECONDS = new TimeUnit(3, "SECONDS") {
159: public long toNanos(long d) {
160: return x(d, C3 / C0, MAX / (C3 / C0));
161: }
162:
163: public long toMicros(long d) {
164: return x(d, C3 / C1, MAX / (C3 / C1));
165: }
166:
167: public long toMillis(long d) {
168: return x(d, C3 / C2, MAX / (C3 / C2));
169: }
170:
171: public long toSeconds(long d) {
172: return d;
173: }
174:
175: public long toMinutes(long d) {
176: return d / (C4 / C3);
177: }
178:
179: public long toHours(long d) {
180: return d / (C5 / C3);
181: }
182:
183: public long toDays(long d) {
184: return d / (C6 / C3);
185: }
186:
187: public long convert(long d, TimeUnit u) {
188: return u.toSeconds(d);
189: }
190:
191: int excessNanos(long d, long m) {
192: return 0;
193: }
194: };
195: public static final TimeUnit MINUTES = new TimeUnit(4, "MINUTES") {
196: public long toNanos(long d) {
197: return x(d, C4 / C0, MAX / (C4 / C0));
198: }
199:
200: public long toMicros(long d) {
201: return x(d, C4 / C1, MAX / (C4 / C1));
202: }
203:
204: public long toMillis(long d) {
205: return x(d, C4 / C2, MAX / (C4 / C2));
206: }
207:
208: public long toSeconds(long d) {
209: return x(d, C4 / C3, MAX / (C4 / C3));
210: }
211:
212: public long toMinutes(long d) {
213: return d;
214: }
215:
216: public long toHours(long d) {
217: return d / (C5 / C4);
218: }
219:
220: public long toDays(long d) {
221: return d / (C6 / C4);
222: }
223:
224: public long convert(long d, TimeUnit u) {
225: return u.toMinutes(d);
226: }
227:
228: int excessNanos(long d, long m) {
229: return 0;
230: }
231: };
232: public static final TimeUnit HOURS = new TimeUnit(5, "HOURS") {
233: public long toNanos(long d) {
234: return x(d, C5 / C0, MAX / (C5 / C0));
235: }
236:
237: public long toMicros(long d) {
238: return x(d, C5 / C1, MAX / (C5 / C1));
239: }
240:
241: public long toMillis(long d) {
242: return x(d, C5 / C2, MAX / (C5 / C2));
243: }
244:
245: public long toSeconds(long d) {
246: return x(d, C5 / C3, MAX / (C5 / C3));
247: }
248:
249: public long toMinutes(long d) {
250: return x(d, C5 / C4, MAX / (C5 / C4));
251: }
252:
253: public long toHours(long d) {
254: return d;
255: }
256:
257: public long toDays(long d) {
258: return d / (C6 / C5);
259: }
260:
261: public long convert(long d, TimeUnit u) {
262: return u.toHours(d);
263: }
264:
265: int excessNanos(long d, long m) {
266: return 0;
267: }
268: };
269: public static final TimeUnit DAYS = new TimeUnit(6, "DAYS") {
270: public long toNanos(long d) {
271: return x(d, C6 / C0, MAX / (C6 / C0));
272: }
273:
274: public long toMicros(long d) {
275: return x(d, C6 / C1, MAX / (C6 / C1));
276: }
277:
278: public long toMillis(long d) {
279: return x(d, C6 / C2, MAX / (C6 / C2));
280: }
281:
282: public long toSeconds(long d) {
283: return x(d, C6 / C3, MAX / (C6 / C3));
284: }
285:
286: public long toMinutes(long d) {
287: return x(d, C6 / C4, MAX / (C6 / C4));
288: }
289:
290: public long toHours(long d) {
291: return x(d, C6 / C5, MAX / (C6 / C5));
292: }
293:
294: public long toDays(long d) {
295: return d;
296: }
297:
298: public long convert(long d, TimeUnit u) {
299: return u.toDays(d);
300: }
301:
302: int excessNanos(long d, long m) {
303: return 0;
304: }
305: };
306:
307: private static final TimeUnit[] values = new TimeUnit[] {
308: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES,
309: HOURS, DAYS };
310:
311: public static TimeUnit[] values() {
312: return (TimeUnit[]) values.clone();
313: }
314:
315: /**
316: * The index of this unit. This value is no longer used in this
317: * version of this class, but is retained for serialization
318: * compatibility with previous version.
319: */
320: private final int index;
321:
322: /** name of this unit */
323: private final String name;
324:
325: /** Internal constructor */
326: TimeUnit(int index, String name) {
327: this .index = index;
328: this .name = name;
329: }
330:
331: // Handy constants for conversion methods
332: static final long C0 = 1;
333: static final long C1 = C0 * 1000;
334: static final long C2 = C1 * 1000;
335: static final long C3 = C2 * 1000;
336: static final long C4 = C3 * 60;
337: static final long C5 = C4 * 60;
338: static final long C6 = C5 * 24;
339:
340: static final long MAX = Long.MAX_VALUE;
341:
342: /**
343: * Scale d by m, checking for overflow.
344: * This has a short name to make above code more readable.
345: */
346: static long x(long d, long m, long over) {
347: if (d > over)
348: return Long.MAX_VALUE;
349: if (d < -over)
350: return Long.MIN_VALUE;
351: return d * m;
352: }
353:
354: /**
355: * Convert the given time duration in the given unit to this
356: * unit. Conversions from finer to coarser granularities
357: * truncate, so lose precision. For example converting
358: * <tt>999</tt> milliseconds to seconds results in
359: * <tt>0</tt>. Conversions from coarser to finer granularities
360: * with arguments that would numerically overflow saturate to
361: * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt>
362: * if positive.
363: *
364: * @param duration the time duration in the given <tt>unit</tt>
365: * @param unit the unit of the <tt>duration</tt> argument
366: * @return the converted duration in this unit,
367: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
368: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
369: */
370: public abstract long convert(long duration, TimeUnit unit);
371:
372: /**
373: * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>.
374: * @param duration the duration
375: * @return the converted duration,
376: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
377: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
378: * @see #convert
379: */
380: public abstract long toNanos(long duration);
381:
382: /**
383: * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>.
384: * @param duration the duration
385: * @return the converted duration,
386: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
387: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
388: * @see #convert
389: */
390: public abstract long toMicros(long duration);
391:
392: /**
393: * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>.
394: * @param duration the duration
395: * @return the converted duration,
396: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
397: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
398: * @see #convert
399: */
400: public abstract long toMillis(long duration);
401:
402: /**
403: * Equivalent to <tt>SECONDS.convert(duration, this)</tt>.
404: * @param duration the duration
405: * @return the converted duration,
406: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
407: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
408: * @see #convert
409: */
410: public abstract long toSeconds(long duration);
411:
412: /**
413: * Equivalent to <tt>MINUTES.convert(duration, this)</tt>.
414: * @param duration the duration
415: * @return the converted duration,
416: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
417: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
418: * @see #convert
419: */
420: public abstract long toMinutes(long duration);
421:
422: /**
423: * Equivalent to <tt>HOURS.convert(duration, this)</tt>.
424: * @param duration the duration
425: * @return the converted duration,
426: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
427: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
428: * @see #convert
429: */
430: public abstract long toHours(long duration);
431:
432: /**
433: * Equivalent to <tt>DAYS.convert(duration, this)</tt>.
434: * @param duration the duration
435: * @return the converted duration
436: * @see #convert
437: */
438: public abstract long toDays(long duration);
439:
440: /**
441: * Utility to compute the excess-nanosecond argument to wait,
442: * sleep, join.
443: * @param d the duration
444: * @param m the number of millisecondss
445: * @return the number of nanoseconds
446: */
447: abstract int excessNanos(long d, long m);
448:
449: /**
450: * Perform a timed <tt>Object.wait</tt> using this time unit.
451: * This is a convenience method that converts timeout arguments
452: * into the form required by the <tt>Object.wait</tt> method.
453: *
454: * <p>For example, you could implement a blocking <tt>poll</tt>
455: * method (see {@link BlockingQueue#poll BlockingQueue.poll})
456: * using:
457: *
458: * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException {
459: * while (empty) {
460: * unit.timedWait(this, timeout);
461: * ...
462: * }
463: * }</pre>
464: *
465: * @param obj the object to wait on
466: * @param timeout the maximum time to wait.
467: * @throws InterruptedException if interrupted while waiting.
468: * @see java.lang.Object#wait(long, int)
469: */
470: public void timedWait(Object obj, long timeout)
471: throws InterruptedException {
472: if (timeout > 0) {
473: long ms = toMillis(timeout);
474: int ns = excessNanos(timeout, ms);
475: obj.wait(ms, ns);
476: }
477: }
478:
479: /**
480: * Perform a timed <tt>Thread.join</tt> using this time unit.
481: * This is a convenience method that converts time arguments into the
482: * form required by the <tt>Thread.join</tt> method.
483: * @param thread the thread to wait for
484: * @param timeout the maximum time to wait
485: * @throws InterruptedException if interrupted while waiting.
486: * @see java.lang.Thread#join(long, int)
487: */
488: public void timedJoin(Thread thread, long timeout)
489: throws InterruptedException {
490: if (timeout > 0) {
491: long ms = toMillis(timeout);
492: int ns = excessNanos(timeout, ms);
493: thread.join(ms, ns);
494: }
495: }
496:
497: /**
498: * Perform a <tt>Thread.sleep</tt> using this unit.
499: * This is a convenience method that converts time arguments into the
500: * form required by the <tt>Thread.sleep</tt> method.
501: * @param timeout the minimum time to sleep
502: * @throws InterruptedException if interrupted while sleeping.
503: * @see java.lang.Thread#sleep
504: */
505: public void sleep(long timeout) throws InterruptedException {
506: if (timeout > 0) {
507: long ms = toMillis(timeout);
508: int ns = excessNanos(timeout, ms);
509: Thread.sleep(ms, ns);
510: }
511: }
512:
513: public String toString() {
514: return name;
515: }
516: }
|