- /*
- * @(#)TimeUnit.java 1.6 04/02/09
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package java.util.concurrent;
-
- /**
- * A <tt>TimeUnit</tt> represents time durations at a given unit of
- * granularity and provides utility methods to convert across units,
- * and to perform timing and delay operations in these units. A
- * <tt>TimeUnit</tt> does not maintain time information, but only
- * helps organize and use time representations that may be maintained
- * separately across various contexts.
- *
- * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods
- * how a given timing parameter should be interpreted. For example,
- * the following code will timeout in 50 milliseconds if the {@link
- * java.util.concurrent.locks.Lock lock} is not available:
- *
- * <pre> Lock lock = ...;
- * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
- * </pre>
- * while this code will timeout in 50 seconds:
- * <pre>
- * Lock lock = ...;
- * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ...
- * </pre>
- *
- * Note however, that there is no guarantee that a particular timeout
- * implementation will be able to notice the passage of time at the
- * same granularity as the given <tt>TimeUnit</tt>.
- *
- * @since 1.5
- * @author Doug Lea
- */
- public enum TimeUnit {
- NANOSECONDS(0), MICROSECONDS(1), MILLISECONDS(2), SECONDS(3);
-
- /** the index of this unit */
- private final int index;
-
- /** Internal constructor */
- TimeUnit(int index) {
- this.index = index;
- }
-
- /** Lookup table for conversion factors */
- private static final int[] multipliers = {
- 1,
- 1000,
- 1000 * 1000,
- 1000 * 1000 * 1000
- };
-
- /**
- * Lookup table to check saturation. Note that because we are
- * dividing these down, we don't have to deal with asymmetry of
- * MIN/MAX values.
- */
- private static final long[] overflows = {
- 0, // unused
- Long.MAX_VALUE / 1000,
- Long.MAX_VALUE / (1000 * 1000),
- Long.MAX_VALUE / (1000 * 1000 * 1000)
- };
-
- /**
- * Perform conversion based on given delta representing the
- * difference between units
- * @param delta the difference in index values of source and target units
- * @param duration the duration
- * @return converted duration or saturated value
- */
- private static long doConvert(int delta, long duration) {
- if (delta == 0)
- return duration;
- if (delta < 0)
- return duration / multipliers[-delta];
- if (duration > overflows[delta])
- return Long.MAX_VALUE;
- if (duration < -overflows[delta])
- return Long.MIN_VALUE;
- return duration * multipliers[delta];
- }
-
- /**
- * Convert the given time duration in the given unit to this
- * unit. Conversions from finer to coarser granularities
- * truncate, so lose precision. For example converting
- * <tt>999</tt> milliseconds to seconds results in
- * <tt>0</tt>. Conversions from coarser to finer granularities
- * with arguments that would numerically overflow saturate to
- * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt>
- * if positive.
- *
- * @param duration the time duration in the given <tt>unit</tt>
- * @param unit the unit of the <tt>duration</tt> argument
- * @return the converted duration in this unit,
- * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
- * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
- */
- public long convert(long duration, TimeUnit unit) {
- return doConvert(unit.index - index, duration);
- }
-
- /**
- * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>.
- * @param duration the duration
- * @return the converted duration,
- * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
- * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
- * @see #convert
- */
- public long toNanos(long duration) {
- return doConvert(index, duration);
- }
-
- /**
- * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>.
- * @param duration the duration
- * @return the converted duration,
- * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
- * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
- * @see #convert
- */
- public long toMicros(long duration) {
- return doConvert(index - MICROSECONDS.index, duration);
- }
-
- /**
- * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>.
- * @param duration the duration
- * @return the converted duration,
- * or <tt>Long.MIN_VALUE</tt> if conversion would negatively
- * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
- * @see #convert
- */
- public long toMillis(long duration) {
- return doConvert(index - MILLISECONDS.index, duration);
- }
-
- /**
- * Equivalent to <tt>SECONDS.convert(duration, this)</tt>.
- * @param duration the duration
- * @return the converted duration.
- * @see #convert
- */
- public long toSeconds(long duration) {
- return doConvert(index - SECONDS.index, duration);
- }
-
-
- /**
- * Utility method to compute the excess-nanosecond argument to
- * wait, sleep, join.
- */
- private int excessNanos(long time, long ms) {
- if (this == NANOSECONDS)
- return (int) (time - (ms * 1000 * 1000));
- if (this == MICROSECONDS)
- return (int) ((time * 1000) - (ms * 1000 * 1000));
- return 0;
- }
-
- /**
- * Perform a timed <tt>Object.wait</tt> using this time unit.
- * This is a convenience method that converts timeout arguments
- * into the form required by the <tt>Object.wait</tt> method.
- *
- * <p>For example, you could implement a blocking <tt>poll</tt>
- * method (see {@link BlockingQueue#poll BlockingQueue.poll})
- * using:
- *
- * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException {
- * while (empty) {
- * unit.timedWait(this, timeout);
- * ...
- * }
- * }</pre>
- *
- * @param obj the object to wait on
- * @param timeout the maximum time to wait.
- * @throws InterruptedException if interrupted while waiting.
- * @see Object#wait(long, int)
- */
- public void timedWait(Object obj, long timeout)
- throws InterruptedException {
- if (timeout > 0) {
- long ms = toMillis(timeout);
- int ns = excessNanos(timeout, ms);
- obj.wait(ms, ns);
- }
- }
-
- /**
- * Perform a timed <tt>Thread.join</tt> using this time unit.
- * This is a convenience method that converts time arguments into the
- * form required by the <tt>Thread.join</tt> method.
- * @param thread the thread to wait for
- * @param timeout the maximum time to wait
- * @throws InterruptedException if interrupted while waiting.
- * @see Thread#join(long, int)
- */
- public void timedJoin(Thread thread, long timeout)
- throws InterruptedException {
- if (timeout > 0) {
- long ms = toMillis(timeout);
- int ns = excessNanos(timeout, ms);
- thread.join(ms, ns);
- }
- }
-
- /**
- * Perform a <tt>Thread.sleep</tt> using this unit.
- * This is a convenience method that converts time arguments into the
- * form required by the <tt>Thread.sleep</tt> method.
- * @param timeout the minimum time to sleep
- * @throws InterruptedException if interrupted while sleeping.
- * @see Thread#sleep
- */
- public void sleep(long timeout) throws InterruptedException {
- if (timeout > 0) {
- long ms = toMillis(timeout);
- int ns = excessNanos(timeout, ms);
- Thread.sleep(ms, ns);
- }
- }
-
- }