1/* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/licenses/publicdomain 5 */ 6 7package java.util.concurrent; 8 9/** 10 * A <tt>TimeUnit</tt> represents time durations at a given unit of 11 * granularity and provides utility methods to convert across units, 12 * and to perform timing and delay operations in these units. A 13 * <tt>TimeUnit</tt> does not maintain time information, but only 14 * helps organize and use time representations that may be maintained 15 * separately across various contexts. 16 * 17 * <p>A <tt>TimeUnit</tt> is mainly used to inform time-based methods 18 * how a given timing parameter should be interpreted. For example, 19 * the following code will timeout in 50 milliseconds if the {@link 20 * java.util.concurrent.locks.Lock lock} is not available: 21 * 22 * <pre> Lock lock = ...; 23 * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ... 24 * </pre> 25 * while this code will timeout in 50 seconds: 26 * <pre> 27 * Lock lock = ...; 28 * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ... 29 * </pre> 30 * 31 * Note however, that there is no guarantee that a particular timeout 32 * implementation will be able to notice the passage of time at the 33 * same granularity as the given <tt>TimeUnit</tt>. 34 * 35 * @since 1.5 36 * @author Doug Lea 37 */ 38public enum TimeUnit { 39 /** TimeUnit which represents one nanosecond. */ 40 NANOSECONDS(0), 41 /** TimeUnit which represents one microsecond. */ 42 MICROSECONDS(1), 43 /** TimeUnit which represents one millisecond. */ 44 MILLISECONDS(2), 45 /** TimeUnit which represents one second. */ 46 SECONDS(3); 47 48 /** the index of this unit */ 49 private final int index; 50 51 /** Internal constructor */ 52 TimeUnit(int index) { 53 this.index = index; 54 } 55 56 /** Lookup table for conversion factors */ 57 private static final int[] multipliers = { 58 1, 59 1000, 60 1000 * 1000, 61 1000 * 1000 * 1000 62 }; 63 64 /** 65 * Lookup table to check saturation. Note that because we are 66 * dividing these down, we don't have to deal with asymmetry of 67 * MIN/MAX values. 68 */ 69 private static final long[] overflows = { 70 0, // unused 71 Long.MAX_VALUE / 1000, 72 Long.MAX_VALUE / (1000 * 1000), 73 Long.MAX_VALUE / (1000 * 1000 * 1000) 74 }; 75 76 /** 77 * Perform conversion based on given delta representing the 78 * difference between units 79 * @param delta the difference in index values of source and target units 80 * @param duration the duration 81 * @return converted duration or saturated value 82 */ 83 private static long doConvert(int delta, long duration) { 84 if (delta == 0) 85 return duration; 86 if (delta < 0) 87 return duration / multipliers[-delta]; 88 if (duration > overflows[delta]) 89 return Long.MAX_VALUE; 90 if (duration < -overflows[delta]) 91 return Long.MIN_VALUE; 92 return duration * multipliers[delta]; 93 } 94 95 /** 96 * Convert the given time duration in the given unit to this 97 * unit. Conversions from finer to coarser granularities 98 * truncate, so lose precision. For example converting 99 * <tt>999</tt> milliseconds to seconds results in 100 * <tt>0</tt>. Conversions from coarser to finer granularities 101 * with arguments that would numerically overflow saturate to 102 * <tt>Long.MIN_VALUE</tt> if negative or <tt>Long.MAX_VALUE</tt> 103 * if positive. 104 * 105 * @param duration the time duration in the given <tt>unit</tt> 106 * @param unit the unit of the <tt>duration</tt> argument 107 * @return the converted duration in this unit, 108 * or <tt>Long.MIN_VALUE</tt> if conversion would negatively 109 * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. 110 */ 111 public long convert(long duration, TimeUnit unit) { 112 return doConvert(unit.index - index, duration); 113 } 114 115 /** 116 * Equivalent to <tt>NANOSECONDS.convert(duration, this)</tt>. 117 * @param duration the duration 118 * @return the converted duration, 119 * or <tt>Long.MIN_VALUE</tt> if conversion would negatively 120 * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. 121 * @see #convert 122 */ 123 public long toNanos(long duration) { 124 return doConvert(index, duration); 125 } 126 127 /** 128 * Equivalent to <tt>MICROSECONDS.convert(duration, this)</tt>. 129 * @param duration the duration 130 * @return the converted duration, 131 * or <tt>Long.MIN_VALUE</tt> if conversion would negatively 132 * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. 133 * @see #convert 134 */ 135 public long toMicros(long duration) { 136 return doConvert(index - MICROSECONDS.index, duration); 137 } 138 139 /** 140 * Equivalent to <tt>MILLISECONDS.convert(duration, this)</tt>. 141 * @param duration the duration 142 * @return the converted duration, 143 * or <tt>Long.MIN_VALUE</tt> if conversion would negatively 144 * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow. 145 * @see #convert 146 */ 147 public long toMillis(long duration) { 148 return doConvert(index - MILLISECONDS.index, duration); 149 } 150 151 /** 152 * Equivalent to <tt>SECONDS.convert(duration, this)</tt>. 153 * @param duration the duration 154 * @return the converted duration. 155 * @see #convert 156 */ 157 public long toSeconds(long duration) { 158 return doConvert(index - SECONDS.index, duration); 159 } 160 161 162 /** 163 * Utility method to compute the excess-nanosecond argument to 164 * wait, sleep, join. 165 */ 166 private int excessNanos(long time, long ms) { 167 if (this == NANOSECONDS) 168 return (int) (time - (ms * 1000 * 1000)); 169 if (this == MICROSECONDS) 170 return (int) ((time * 1000) - (ms * 1000 * 1000)); 171 return 0; 172 } 173 174 /** 175 * Perform a timed <tt>Object.wait</tt> using this time unit. 176 * This is a convenience method that converts timeout arguments 177 * into the form required by the <tt>Object.wait</tt> method. 178 * 179 * <p>For example, you could implement a blocking <tt>poll</tt> 180 * method (see {@link BlockingQueue#poll BlockingQueue.poll}) 181 * using: 182 * 183 * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException { 184 * while (empty) { 185 * unit.timedWait(this, timeout); 186 * ... 187 * } 188 * }</pre> 189 * 190 * @param obj the object to wait on 191 * @param timeout the maximum time to wait. 192 * @throws InterruptedException if interrupted while waiting. 193 * @see Object#wait(long, int) 194 */ 195 public void timedWait(Object obj, long timeout) 196 throws InterruptedException { 197 if (timeout > 0) { 198 long ms = toMillis(timeout); 199 int ns = excessNanos(timeout, ms); 200 obj.wait(ms, ns); 201 } 202 } 203 204 /** 205 * Perform a timed <tt>Thread.join</tt> using this time unit. 206 * This is a convenience method that converts time arguments into the 207 * form required by the <tt>Thread.join</tt> method. 208 * @param thread the thread to wait for 209 * @param timeout the maximum time to wait 210 * @throws InterruptedException if interrupted while waiting. 211 * @see Thread#join(long, int) 212 */ 213 public void timedJoin(Thread thread, long timeout) 214 throws InterruptedException { 215 if (timeout > 0) { 216 long ms = toMillis(timeout); 217 int ns = excessNanos(timeout, ms); 218 thread.join(ms, ns); 219 } 220 } 221 222 /** 223 * Perform a <tt>Thread.sleep</tt> using this unit. 224 * This is a convenience method that converts time arguments into the 225 * form required by the <tt>Thread.sleep</tt> method. 226 * @param timeout the minimum time to sleep 227 * @throws InterruptedException if interrupted while sleeping. 228 * @see Thread#sleep 229 */ 230 public void sleep(long timeout) throws InterruptedException { 231 if (timeout > 0) { 232 long ms = toMillis(timeout); 233 int ns = excessNanos(timeout, ms); 234 Thread.sleep(ms, ns); 235 } 236 } 237 238} 239