| /* |
| * 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 <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 { |
| /** TimeUnit which represents one nanosecond. */ |
| NANOSECONDS(0), |
| /** TimeUnit which represents one microsecond. */ |
| MICROSECONDS(1), |
| /** TimeUnit which represents one millisecond. */ |
| MILLISECONDS(2), |
| /** TimeUnit which represents one second. */ |
| 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); |
| } |
| } |
| |
| } |