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 <em>monitor</em> 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 ignored) { 106 // timeout not reached 107 } 108 } 109 }