ThreadMonitor.java

  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. import java.time.Duration;

  19. /**
  20.  * Monitors a thread, interrupting it if it reaches the specified timeout.
  21.  * <p>
  22.  * This works by sleeping until the specified timeout amount and then interrupting the thread being monitored. If the
  23.  * thread being monitored completes its work before being interrupted, it should {@code interrupt()} the <em>monitor</em>
  24.  * thread.
  25.  * </p>
  26.  *
  27.  * <pre>
  28.  * Duration timeout = Duration.ofSeconds(1);
  29.  * try {
  30.  *     Thread monitor = ThreadMonitor.start(timeout);
  31.  *     // do some work here
  32.  *     ThreadMonitor.stop(monitor);
  33.  * } catch (InterruptedException e) {
  34.  *     // timed amount was reached
  35.  * }
  36.  * </pre>
  37.  */
  38. final class ThreadMonitor implements Runnable {

  39.     /**
  40.      * Starts monitoring the current thread.
  41.      *
  42.      * @param timeout The timeout amount. or no timeout if the value is zero or less.
  43.      * @return The monitor thread or {@code null} if the timeout amount is not greater than zero.
  44.      */
  45.     static Thread start(final Duration timeout) {
  46.         return start(Thread.currentThread(), timeout);
  47.     }

  48.     /**
  49.      * Starts monitoring the specified thread.
  50.      *
  51.      * @param thread The thread to monitor
  52.      * @param timeout The timeout amount. or no timeout if the value is zero or less.
  53.      * @return The monitor thread or {@code null} if the timeout amount is not greater than zero.
  54.      */
  55.     static Thread start(final Thread thread, final Duration timeout) {
  56.         if (timeout.isZero() || timeout.isNegative()) {
  57.             return null;
  58.         }
  59.         final Thread monitor = new Thread(new ThreadMonitor(thread, timeout), ThreadMonitor.class.getSimpleName());
  60.         monitor.setDaemon(true);
  61.         monitor.start();
  62.         return monitor;
  63.     }

  64.     /**
  65.      * Stops monitoring the specified thread.
  66.      *
  67.      * @param thread The monitor thread, may be {@code null}.
  68.      */
  69.     static void stop(final Thread thread) {
  70.         if (thread != null) {
  71.             thread.interrupt();
  72.         }
  73.     }

  74.     private final Thread thread;

  75.     private final Duration timeout;

  76.     /**
  77.      * Constructs a new monitor.
  78.      *
  79.      * @param thread The thread to monitor.
  80.      * @param timeout The timeout amount.
  81.      */
  82.     private ThreadMonitor(final Thread thread, final Duration timeout) {
  83.         this.thread = thread;
  84.         this.timeout = timeout;
  85.     }

  86.     /**
  87.      * Sleeps until the specified timeout amount and then interrupt the thread being monitored.
  88.      *
  89.      * @see Runnable#run()
  90.      */
  91.     @Override
  92.     public void run() {
  93.         try {
  94.             ThreadUtils.sleep(timeout);
  95.             thread.interrupt();
  96.         } catch (final InterruptedException ignored) {
  97.             // timeout not reached
  98.         }
  99.     }
  100. }