1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.io;
18
19 import java.time.Duration;
20 import java.time.Instant;
21
22 /**
23 * Helps work with threads.
24 *
25 * @since 2.12.0
26 */
27 public final class ThreadUtils {
28
29 private static int getNanosOfMilli(final Duration duration) {
30 return duration.getNano() % 1_000_000;
31 }
32
33 /**
34 * Sleeps for a guaranteed minimum duration unless interrupted.
35 * <p>
36 * This method exists because Thread.sleep(100) can sleep for 0, 70, 100 or 200ms or anything else it deems appropriate. Read
37 * {@link Thread#sleep(long, int)}} for further interesting details.
38 * </p>
39 *
40 * @param duration the sleep duration.
41 * @throws InterruptedException if interrupted.
42 * @see Thread#sleep(long, int)
43 */
44 public static void sleep(final Duration duration) throws InterruptedException {
45 // Using this method avoids depending on the vagaries of the precision and accuracy of system timers and schedulers.
46 try {
47 // Use the JVM elapsed time, avoids issues with DST changes and manual OS time changes.
48 final long nanoStart = System.nanoTime();
49 final long finishNanos = nanoStart + duration.toNanos(); // toNanos(): Possible ArithmeticException, otherwise wrap around OK.
50 Duration remainingDuration = duration;
51 long nowNano;
52 do {
53 Thread.sleep(remainingDuration.toMillis(), getNanosOfMilli(remainingDuration));
54 nowNano = System.nanoTime();
55 remainingDuration = Duration.ofNanos(finishNanos - nowNano);
56 } while (nowNano - finishNanos < 0); // handles wrap around, see Thread#sleep(long, int).
57 } catch (final ArithmeticException e) {
58 // Use the current time
59 final Instant finishInstant = Instant.now().plus(duration);
60 Duration remainingDuration = duration;
61 do {
62 Thread.sleep(remainingDuration.toMillis(), getNanosOfMilli(remainingDuration));
63 remainingDuration = Duration.between(Instant.now(), finishInstant);
64 } while (!remainingDuration.isNegative());
65 }
66 }
67
68 /**
69 * Make private in 3.0.
70 *
71 * @deprecated TODO Make private in 3.0.
72 */
73 @Deprecated
74 public ThreadUtils() {
75 // empty
76 }
77 }