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 java.util.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.
016: *
017: * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods
018: * how a given timing parameter should be interpreted. For example,
019: * the following code will timeout in 50 milliseconds if the {@link
020: * java.util.concurrent.locks.Lock lock} is not available:
021: *
022: * <pre> Lock lock = ...;
023: * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
024: * </pre>
025: * while this code will timeout in 50 seconds:
026: * <pre>
027: * Lock lock = ...;
028: * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ...
029: * </pre>
030: *
031: * Note however, that there is no guarantee that a particular timeout
032: * implementation will be able to notice the passage of time at the
033: * same granularity as the given <tt>TimeUnit</tt>.
034: *
035: * @since 1.5
036: * @author Doug Lea
037: */
038: public enum TimeUnit {
039: NANOSECONDS(0), MICROSECONDS(1), MILLISECONDS(2), SECONDS(3);
040:
041: /** the index of this unit */
042: private final int index;
043:
044: /** Internal constructor */
045: TimeUnit(int index) {
046: this .index = index;
047: }
048:
049: /** Lookup table for conversion factors */
050: private static final int[] multipliers = { 1, 1000, 1000 * 1000,
051: 1000 * 1000 * 1000 };
052:
053: /**
054: * Lookup table to check saturation. Note that because we are
055: * dividing these down, we don't have to deal with asymmetry of
056: * MIN/MAX values.
057: */
058: private static final long[] overflows = {
059: 0, // unused
060: Long.MAX_VALUE / 1000, Long.MAX_VALUE / (1000 * 1000),
061: Long.MAX_VALUE / (1000 * 1000 * 1000) };
062:
063: /**
064: * Perform conversion based on given delta representing the
065: * difference between units
066: * @param delta the difference in index values of source and target units
067: * @param duration the duration
068: * @return converted duration or saturated value
069: */
070: private static long doConvert(int delta, long duration) {
071: if (delta == 0)
072: return duration;
073: if (delta < 0)
074: return duration / multipliers[-delta];
075: if (duration > overflows[delta])
076: return Long.MAX_VALUE;
077: if (duration < -overflows[delta])
078: return Long.MIN_VALUE;
079: return duration * multipliers[delta];
080: }
081:
082: /**
083: * Convert the given time duration in the given unit to this
084: * unit. Conversions from finer to coarser granularities
085: * truncate, so lose precision. For example converting
086: * <tt>999</tt> milliseconds to seconds results in
087: * <tt>0</tt>. Conversions from coarser to finer granularities
088: * with arguments that would numerically overflow saturate to
089: * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt>
090: * if positive.
091: *
092: * @param duration the time duration in the given <tt>unit</tt>
093: * @param unit the unit of the <tt>duration</tt> argument
094: * @return the converted duration in this unit,
095: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
096: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
097: */
098: public long convert(long duration, TimeUnit unit) {
099: return doConvert(unit.index - index, duration);
100: }
101:
102: /**
103: * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>.
104: * @param duration the duration
105: * @return the converted duration,
106: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
107: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
108: * @see #convert
109: */
110: public long toNanos(long duration) {
111: return doConvert(index, duration);
112: }
113:
114: /**
115: * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>.
116: * @param duration the duration
117: * @return the converted duration,
118: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
119: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
120: * @see #convert
121: */
122: public long toMicros(long duration) {
123: return doConvert(index - MICROSECONDS.index, duration);
124: }
125:
126: /**
127: * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>.
128: * @param duration the duration
129: * @return the converted duration,
130: * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
131: * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
132: * @see #convert
133: */
134: public long toMillis(long duration) {
135: return doConvert(index - MILLISECONDS.index, duration);
136: }
137:
138: /**
139: * Equivalent to <tt>SECONDS.convert(duration, this)</tt>.
140: * @param duration the duration
141: * @return the converted duration.
142: * @see #convert
143: */
144: public long toSeconds(long duration) {
145: return doConvert(index - SECONDS.index, duration);
146: }
147:
148: /**
149: * Utility method to compute the excess-nanosecond argument to
150: * wait, sleep, join.
151: */
152: private int excessNanos(long time, long ms) {
153: if (this == NANOSECONDS)
154: return (int) (time - (ms * 1000 * 1000));
155: if (this == MICROSECONDS)
156: return (int) ((time * 1000) - (ms * 1000 * 1000));
157: return 0;
158: }
159:
160: /**
161: * Perform a timed <tt>Object.wait</tt> using this time unit.
162: * This is a convenience method that converts timeout arguments
163: * into the form required by the <tt>Object.wait</tt> method.
164: *
165: * <p>For example, you could implement a blocking <tt>poll</tt>
166: * method (see {@link BlockingQueue#poll BlockingQueue.poll})
167: * using:
168: *
169: * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException {
170: * while (empty) {
171: * unit.timedWait(this, timeout);
172: * ...
173: * }
174: * }</pre>
175: *
176: * @param obj the object to wait on
177: * @param timeout the maximum time to wait.
178: * @throws InterruptedException if interrupted while waiting.
179: * @see Object#wait(long, int)
180: */
181: public void timedWait(Object obj, long timeout)
182: throws InterruptedException {
183: if (timeout > 0) {
184: long ms = toMillis(timeout);
185: int ns = excessNanos(timeout, ms);
186: obj.wait(ms, ns);
187: }
188: }
189:
190: /**
191: * Perform a timed <tt>Thread.join</tt> using this time unit.
192: * This is a convenience method that converts time arguments into the
193: * form required by the <tt>Thread.join</tt> method.
194: * @param thread the thread to wait for
195: * @param timeout the maximum time to wait
196: * @throws InterruptedException if interrupted while waiting.
197: * @see Thread#join(long, int)
198: */
199: public void timedJoin(Thread thread, long timeout)
200: throws InterruptedException {
201: if (timeout > 0) {
202: long ms = toMillis(timeout);
203: int ns = excessNanos(timeout, ms);
204: thread.join(ms, ns);
205: }
206: }
207:
208: /**
209: * Perform a <tt>Thread.sleep</tt> using this unit.
210: * This is a convenience method that converts time arguments into the
211: * form required by the <tt>Thread.sleep</tt> method.
212: * @param timeout the minimum time to sleep
213: * @throws InterruptedException if interrupted while sleeping.
214: * @see Thread#sleep
215: */
216: public void sleep(long timeout) throws InterruptedException {
217: if (timeout > 0) {
218: long ms = toMillis(timeout);
219: int ns = excessNanos(timeout, ms);
220: Thread.sleep(ms, ns);
221: }
222: }
223:
224: }
|