View Javadoc
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    *      http://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  
21  /**
22   * Monitors a thread, interrupting it if it reaches the specified timeout.
23   * <p>
24   * This works by sleeping until the specified timeout amount and then interrupting the thread being monitored. If the
25   * thread being monitored completes its work before being interrupted, it should {@code interrupt()} the <i>monitor</i>
26   * thread.
27   * </p>
28   *
29   * <pre>
30   * Duration timeout = Duration.ofSeconds(1);
31   * try {
32   *     Thread monitor = ThreadMonitor.start(timeout);
33   *     // do some work here
34   *     ThreadMonitor.stop(monitor);
35   * } catch (InterruptedException e) {
36   *     // timed amount was reached
37   * }
38   * </pre>
39   */
40  final class ThreadMonitor implements Runnable {
41  
42      /**
43       * Starts monitoring the current thread.
44       *
45       * @param timeout The timeout amount. or no timeout if the value is zero or less.
46       * @return The monitor thread or {@code null} if the timeout amount is not greater than zero.
47       */
48      static Thread start(final Duration timeout) {
49          return start(Thread.currentThread(), timeout);
50      }
51  
52      /**
53       * Starts monitoring the specified thread.
54       *
55       * @param thread The thread to monitor
56       * @param timeout The timeout amount. or no timeout if the value is zero or less.
57       * @return The monitor thread or {@code null} if the timeout amount is not greater than zero.
58       */
59      static Thread start(final Thread thread, final Duration timeout) {
60          if (timeout.isZero() || timeout.isNegative()) {
61              return null;
62          }
63          final Thread monitor = new Thread(new ThreadMonitor(thread, timeout), ThreadMonitor.class.getSimpleName());
64          monitor.setDaemon(true);
65          monitor.start();
66          return monitor;
67      }
68  
69      /**
70       * Stops monitoring the specified thread.
71       *
72       * @param thread The monitor thread, may be {@code null}.
73       */
74      static void stop(final Thread thread) {
75          if (thread != null) {
76              thread.interrupt();
77          }
78      }
79  
80      private final Thread thread;
81  
82      private final Duration timeout;
83  
84      /**
85       * Constructs a new monitor.
86       *
87       * @param thread The thread to monitor.
88       * @param timeout The timeout amount.
89       */
90      private ThreadMonitor(final Thread thread, final Duration timeout) {
91          this.thread = thread;
92          this.timeout = timeout;
93      }
94  
95      /**
96       * Sleeps until the specified timeout amount and then interrupt the thread being monitored.
97       *
98       * @see Runnable#run()
99       */
100     @Override
101     public void run() {
102         try {
103             ThreadUtils.sleep(timeout);
104             thread.interrupt();
105         } catch (final InterruptedException e) {
106             // timeout not reached
107         }
108     }
109 }