/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ package java.util.concurrent; /** * A TimeUnit 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 * TimeUnit does not maintain time information, but only * helps organize and use time representations that may be maintained * separately across various contexts. * *

A TimeUnit 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: * *

  Lock lock = ...;
 *  if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ...
 * 
* while this code will timeout in 50 seconds: *
 *  Lock lock = ...;
 *  if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ...
 * 
* * 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 TimeUnit. * * @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 * 999 milliseconds to seconds results in * 0. Conversions from coarser to finer granularities * with arguments that would numerically overflow saturate to * Long.MIN_VALUE if negative or Long.MAX_VALUE * if positive. * * @param duration the time duration in the given unit * @param unit the unit of the duration argument * @return the converted duration in this unit, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. */ public long convert(long duration, TimeUnit unit) { return doConvert(unit.index - index, duration); } /** * Equivalent to NANOSECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ public long toNanos(long duration) { return doConvert(index, duration); } /** * Equivalent to MICROSECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ public long toMicros(long duration) { return doConvert(index - MICROSECONDS.index, duration); } /** * Equivalent to MILLISECONDS.convert(duration, this). * @param duration the duration * @return the converted duration, * or Long.MIN_VALUE if conversion would negatively * overflow, or Long.MAX_VALUE if it would positively overflow. * @see #convert */ public long toMillis(long duration) { return doConvert(index - MILLISECONDS.index, duration); } /** * Equivalent to SECONDS.convert(duration, this). * @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 Object.wait using this time unit. * This is a convenience method that converts timeout arguments * into the form required by the Object.wait method. * *

For example, you could implement a blocking poll * method (see {@link BlockingQueue#poll BlockingQueue.poll}) * using: * *

  public synchronized  Object poll(long timeout, TimeUnit unit) throws InterruptedException {
     *    while (empty) {
     *      unit.timedWait(this, timeout);
     *      ...
     *    }
     *  }
* * @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 Thread.join using this time unit. * This is a convenience method that converts time arguments into the * form required by the Thread.join 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 Thread.sleep using this unit. * This is a convenience method that converts time arguments into the * form required by the Thread.sleep 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); } } }