ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk8/java/util/concurrent/TimeUnit.java
Revision: 1.2
Committed: Sat Mar 26 12:02:03 2016 UTC (8 years, 2 months ago) by dl
Branch: MAIN
Changes since 1.1: +32 -16 lines
Log Message:
use jdk8 @Contended

File Contents

# Content
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/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent;
8
9 import java.time.temporal.ChronoUnit;
10 import java.util.Objects;
11
12 /**
13 * A {@code TimeUnit} represents time durations at a given unit of
14 * granularity and provides utility methods to convert across units,
15 * and to perform timing and delay operations in these units. A
16 * {@code TimeUnit} does not maintain time information, but only
17 * helps organize and use time representations that may be maintained
18 * separately across various contexts. A nanosecond is defined as one
19 * thousandth of a microsecond, a microsecond as one thousandth of a
20 * millisecond, a millisecond as one thousandth of a second, a minute
21 * as sixty seconds, an hour as sixty minutes, and a day as twenty four
22 * hours.
23 *
24 * <p>A {@code TimeUnit} is mainly used to inform time-based methods
25 * how a given timing parameter should be interpreted. For example,
26 * the following code will timeout in 50 milliseconds if the {@link
27 * java.util.concurrent.locks.Lock lock} is not available:
28 *
29 * <pre> {@code
30 * Lock lock = ...;
31 * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
32 *
33 * while this code will timeout in 50 seconds:
34 * <pre> {@code
35 * Lock lock = ...;
36 * if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
37 *
38 * Note however, that there is no guarantee that a particular timeout
39 * implementation will be able to notice the passage of time at the
40 * same granularity as the given {@code TimeUnit}.
41 *
42 * @since 1.5
43 * @author Doug Lea
44 */
45 public enum TimeUnit {
46 /**
47 * Time unit representing one thousandth of a microsecond.
48 */
49 NANOSECONDS(1L), // (cannot use symbolic scale names here)
50 /**
51 * Time unit representing one thousandth of a millisecond.
52 */
53 MICROSECONDS(1000L),
54 /**
55 * Time unit representing one thousandth of a second.
56 */
57 MILLISECONDS(1000L * 1000L),
58 /**
59 * Time unit representing one second.
60 */
61 SECONDS(1000L * 1000L * 1000L),
62 /**
63 * Time unit representing sixty seconds.
64 * @since 1.6
65 */
66 MINUTES(1000L * 1000L * 1000L * 60L),
67 /**
68 * Time unit representing sixty minutes.
69 * @since 1.6
70 */
71 HOURS(1000L * 1000L * 1000L * 60L * 60L),
72 /**
73 * Time unit representing twenty four hours.
74 * @since 1.6
75 */
76 DAYS(1000L * 1000L * 1000L * 60L * 60L * 24L);
77
78 // Scales as constants
79 private static final long NANO_SCALE = 1L;
80 private static final long MICRO_SCALE = 1000L * NANO_SCALE;
81 private static final long MILLI_SCALE = 1000L * MICRO_SCALE;
82 private static final long SECOND_SCALE = 1000L * MILLI_SCALE;
83 private static final long MINUTE_SCALE = 60L * SECOND_SCALE;
84 private static final long HOUR_SCALE = 60L * MINUTE_SCALE;
85 private static final long DAY_SCALE = 24L * HOUR_SCALE;
86
87 /*
88 * Instances cache conversion ratios and saturation cutoffs for
89 * the units up through SECONDS. Other cases compute them, in
90 * method cvt.
91 */
92
93 private final long scale;
94 private final long maxNanos;
95 private final long maxMicros;
96 private final long maxMillis;
97 private final long maxSecs;
98 private final long microRatio;
99 private final int milliRatio; // fits in 32 bits
100 private final int secRatio; // fits in 32 bits
101
102 TimeUnit(long s) {
103 this.scale = s;
104 this.maxNanos = Long.MAX_VALUE / s;
105 long ur = (s >= MICRO_SCALE) ? (s / MICRO_SCALE) : (MICRO_SCALE / s);
106 this.microRatio = ur;
107 this.maxMicros = Long.MAX_VALUE / ur;
108 long mr = (scale >= MILLI_SCALE) ? (s / MILLI_SCALE) : (MILLI_SCALE / s);
109 this.milliRatio = (int)mr;
110 this.maxMillis = Long.MAX_VALUE / mr;
111 long sr = (s >= SECOND_SCALE) ? (s / SECOND_SCALE) : (SECOND_SCALE / s);
112 this.secRatio = (int)sr;
113 this.maxSecs = Long.MAX_VALUE / sr;
114 }
115
116 /**
117 * General conversion utility.
118 *
119 * @param d duration
120 * @param dst result scale unit
121 * @param src source scale unit
122 */
123 private static long cvt(long d, long dst, long src) {
124 long r, m;
125 if (src == dst)
126 return d;
127 else if (src < dst)
128 return d / (dst / src);
129 else if (d > (m = Long.MAX_VALUE / (r = src / dst)))
130 return Long.MAX_VALUE;
131 else if (d < -m)
132 return Long.MIN_VALUE;
133 else
134 return d * r;
135 }
136
137 /**
138 * Converts the given time duration in the given unit to this unit.
139 * Conversions from finer to coarser granularities truncate, so
140 * lose precision. For example, converting {@code 999} milliseconds
141 * to seconds results in {@code 0}. Conversions from coarser to
142 * finer granularities with arguments that would numerically
143 * overflow saturate to {@code Long.MIN_VALUE} if negative or
144 * {@code Long.MAX_VALUE} if positive.
145 *
146 * <p>For example, to convert 10 minutes to milliseconds, use:
147 * {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)}
148 *
149 * @param sourceDuration the time duration in the given {@code sourceUnit}
150 * @param sourceUnit the unit of the {@code sourceDuration} argument
151 * @return the converted duration in this unit,
152 * or {@code Long.MIN_VALUE} if conversion would negatively
153 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
154 */
155 public long convert(long sourceDuration, TimeUnit sourceUnit) {
156 switch (this) {
157 case NANOSECONDS: return sourceUnit.toNanos(sourceDuration);
158 case MICROSECONDS: return sourceUnit.toMicros(sourceDuration);
159 case MILLISECONDS: return sourceUnit.toMillis(sourceDuration);
160 case SECONDS: return sourceUnit.toSeconds(sourceDuration);
161 default: return cvt(sourceDuration, scale, sourceUnit.scale);
162 }
163 }
164
165 /**
166 * Equivalent to
167 * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
168 * @param duration the duration
169 * @return the converted duration,
170 * or {@code Long.MIN_VALUE} if conversion would negatively
171 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
172 */
173 public long toNanos(long duration) {
174 long s, m;
175 if ((s = scale) == NANO_SCALE)
176 return duration;
177 else if (duration > (m = maxNanos))
178 return Long.MAX_VALUE;
179 else if (duration < -m)
180 return Long.MIN_VALUE;
181 else
182 return duration * s;
183 }
184
185 /**
186 * Equivalent to
187 * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
188 * @param duration the duration
189 * @return the converted duration,
190 * or {@code Long.MIN_VALUE} if conversion would negatively
191 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
192 */
193 public long toMicros(long duration) {
194 long s, m;
195 if ((s = scale) == MICRO_SCALE)
196 return duration;
197 else if (s < MICRO_SCALE)
198 return duration / microRatio;
199 else if (duration > (m = maxMicros))
200 return Long.MAX_VALUE;
201 else if (duration < -m)
202 return Long.MIN_VALUE;
203 else
204 return duration * microRatio;
205 }
206
207 /**
208 * Equivalent to
209 * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
210 * @param duration the duration
211 * @return the converted duration,
212 * or {@code Long.MIN_VALUE} if conversion would negatively
213 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
214 */
215 public long toMillis(long duration) {
216 long s, m;
217 if ((s = scale) == MILLI_SCALE)
218 return duration;
219 else if (s < MILLI_SCALE)
220 return duration / milliRatio;
221 else if (duration > (m = maxMillis))
222 return Long.MAX_VALUE;
223 else if (duration < -m)
224 return Long.MIN_VALUE;
225 else
226 return duration * milliRatio;
227 }
228
229 /**
230 * Equivalent to
231 * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
232 * @param duration the duration
233 * @return the converted duration,
234 * or {@code Long.MIN_VALUE} if conversion would negatively
235 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
236 */
237 public long toSeconds(long duration) {
238 long s, m;
239 if ((s = scale) == SECOND_SCALE)
240 return duration;
241 else if (s < SECOND_SCALE)
242 return duration / secRatio;
243 else if (duration > (m = maxSecs))
244 return Long.MAX_VALUE;
245 else if (duration < -m)
246 return Long.MIN_VALUE;
247 else
248 return duration * secRatio;
249 }
250
251 /**
252 * Equivalent to
253 * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
254 * @param duration the duration
255 * @return the converted duration,
256 * or {@code Long.MIN_VALUE} if conversion would negatively
257 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
258 * @since 1.6
259 */
260 public long toMinutes(long duration) {
261 return cvt(duration, MINUTE_SCALE, scale);
262 }
263
264 /**
265 * Equivalent to
266 * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
267 * @param duration the duration
268 * @return the converted duration,
269 * or {@code Long.MIN_VALUE} if conversion would negatively
270 * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
271 * @since 1.6
272 */
273 public long toHours(long duration) {
274 return cvt(duration, HOUR_SCALE, scale);
275 }
276
277 /**
278 * Equivalent to
279 * {@link #convert(long, TimeUnit) DAYS.convert(duration, this)}.
280 * @param duration the duration
281 * @return the converted duration
282 * @since 1.6
283 */
284 public long toDays(long duration) {
285 return cvt(duration, DAY_SCALE, scale);
286 }
287
288 /**
289 * Utility to compute the excess-nanosecond argument to wait,
290 * sleep, join.
291 * @param d the duration
292 * @param m the number of milliseconds
293 * @return the number of nanoseconds
294 */
295 private int excessNanos(long d, long m) {
296 long s;
297 if ((s = scale) == NANO_SCALE)
298 return (int)(d - (m * MILLI_SCALE));
299 else if (s == MICRO_SCALE)
300 return (int)((d * 1000L) - (m * MILLI_SCALE));
301 else
302 return 0;
303 }
304
305 /**
306 * Performs a timed {@link Object#wait(long, int) Object.wait}
307 * using this time unit.
308 * This is a convenience method that converts timeout arguments
309 * into the form required by the {@code Object.wait} method.
310 *
311 * <p>For example, you could implement a blocking {@code poll}
312 * method (see {@link BlockingQueue#poll BlockingQueue.poll})
313 * using:
314 *
315 * <pre> {@code
316 * public synchronized Object poll(long timeout, TimeUnit unit)
317 * throws InterruptedException {
318 * while (empty) {
319 * unit.timedWait(this, timeout);
320 * ...
321 * }
322 * }}</pre>
323 *
324 * @param obj the object to wait on
325 * @param timeout the maximum time to wait. If less than
326 * or equal to zero, do not wait at all.
327 * @throws InterruptedException if interrupted while waiting
328 */
329 public void timedWait(Object obj, long timeout)
330 throws InterruptedException {
331 if (timeout > 0) {
332 long ms = toMillis(timeout);
333 int ns = excessNanos(timeout, ms);
334 obj.wait(ms, ns);
335 }
336 }
337
338 /**
339 * Performs a timed {@link Thread#join(long, int) Thread.join}
340 * using this time unit.
341 * This is a convenience method that converts time arguments into the
342 * form required by the {@code Thread.join} method.
343 *
344 * @param thread the thread to wait for
345 * @param timeout the maximum time to wait. If less than
346 * or equal to zero, do not wait at all.
347 * @throws InterruptedException if interrupted while waiting
348 */
349 public void timedJoin(Thread thread, long timeout)
350 throws InterruptedException {
351 if (timeout > 0) {
352 long ms = toMillis(timeout);
353 int ns = excessNanos(timeout, ms);
354 thread.join(ms, ns);
355 }
356 }
357
358 /**
359 * Performs a {@link Thread#sleep(long, int) Thread.sleep} using
360 * this time unit.
361 * This is a convenience method that converts time arguments into the
362 * form required by the {@code Thread.sleep} method.
363 *
364 * @param timeout the minimum time to sleep. If less than
365 * or equal to zero, do not sleep at all.
366 * @throws InterruptedException if interrupted while sleeping
367 */
368 public void sleep(long timeout) throws InterruptedException {
369 if (timeout > 0) {
370 long ms = toMillis(timeout);
371 int ns = excessNanos(timeout, ms);
372 Thread.sleep(ms, ns);
373 }
374 }
375
376 /**
377 * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
378 *
379 * @return the converted equivalent ChronoUnit
380 * @since 9
381 */
382 public ChronoUnit toChronoUnit() {
383 switch (this) {
384 case NANOSECONDS: return ChronoUnit.NANOS;
385 case MICROSECONDS: return ChronoUnit.MICROS;
386 case MILLISECONDS: return ChronoUnit.MILLIS;
387 case SECONDS: return ChronoUnit.SECONDS;
388 case MINUTES: return ChronoUnit.MINUTES;
389 case HOURS: return ChronoUnit.HOURS;
390 case DAYS: return ChronoUnit.DAYS;
391 default: throw new AssertionError();
392 }
393 }
394
395 /**
396 * Converts a {@code ChronoUnit} to the equivalent {@code TimeUnit}.
397 *
398 * @param chronoUnit the ChronoUnit to convert
399 * @return the converted equivalent TimeUnit
400 * @throws IllegalArgumentException if {@code chronoUnit} has no
401 * equivalent TimeUnit
402 * @throws NullPointerException if {@code chronoUnit} is null
403 * @since 9
404 */
405 public static TimeUnit of(ChronoUnit chronoUnit) {
406 switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
407 case NANOS: return TimeUnit.NANOSECONDS;
408 case MICROS: return TimeUnit.MICROSECONDS;
409 case MILLIS: return TimeUnit.MILLISECONDS;
410 case SECONDS: return TimeUnit.SECONDS;
411 case MINUTES: return TimeUnit.MINUTES;
412 case HOURS: return TimeUnit.HOURS;
413 case DAYS: return TimeUnit.DAYS;
414 default:
415 throw new IllegalArgumentException(
416 "No TimeUnit equivalent for " + chronoUnit);
417 }
418 }
419
420 }