How to timeout a thread
我想运行一个线程一段固定的时间。如果在这段时间内没有完成,我想要么杀死它,抛出一些异常,要么以某种方式处理它。怎么做?
我从这条线索中发现的一种方法在线程的run()方法中使用timertask。
有没有更好的解决办法?
nbsp;编辑:添加一个赏金,因为我需要一个更清楚的答案。下面给出的ExecutorService代码不能解决我的问题。为什么我要在执行(一些代码——我没有处理这段代码)之后休眠()?如果代码完成并且sleep()被中断,怎么可能是超时?
需要执行的任务不在我的控制范围内。它可以是任何代码。问题是这段代码可能会进入无限循环。我不想那样。所以,我只想在一个单独的线程中运行该任务。父线程必须等待该线程完成并需要知道任务的状态(即是否超时或发生了异常或是否成功)。如果任务进入无限循环,我的父线程将无限期地继续等待,这不是一个理想的情况。
实际上,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package com.stackoverflow.q2275443; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class Test { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(new Task()); try { System.out.println("Started.."); System.out.println(future.get(3, TimeUnit.SECONDS)); System.out.println("Finished!"); } catch (TimeoutException e) { future.cancel(true); System.out.println("Terminated!"); } executor.shutdownNow(); } } class Task implements Callable<String> { @Override public String call() throws Exception { Thread.sleep(4000); // Just to demo a long running task of 4 seconds. return"Ready!"; } } |
在
更新:为了澄清概念上的误解,不需要使用
1 2 3 |
没有一种100%可靠的方法来完成任何旧任务。这项任务必须牢记这一能力。
核心的Java库,如EDCOX1,4,用EDCOX1,5个调用在工作者线程上取消异步任务。因此,例如,如果任务包含某种循环,您应该在每次迭代时检查它的中断状态。如果任务正在执行I/O操作,它们也应该是可中断的,并且设置该操作可能很棘手。在任何情况下,请记住,代码必须主动检查中断;设置中断不一定要做任何事情。
当然,如果您的任务是一个简单的循环,那么您可以在每次迭代时检查当前时间,并在指定的超时时间结束时放弃。在这种情况下不需要工作线程。
考虑使用ExecutorService实例。
当前线程将一直阻塞,直到该方法完成(不确定是否需要这样做),这可能是因为任务正常完成或已达到超时。您可以检查返回的
BalusC说:
Update: to clarify a conceptual misunderstanding, the sleep() is not required. It is just used for SSCCE/demonstration purposes. Just do your long running task right there in place of sleep().
但是如果用
如果线程是可中断的,则需要抛出一个
我觉得这是个严重的问题。我看不出如何使这个答案适应一般长期任务。
编辑后添加:我将其重新定义为一个新问题:[在固定时间后中断线程,是否必须引发InterruptedException?]
假设线程代码超出您的控制范围:
从上面提到的Java文档:
What if a thread doesn't respond to Thread.interrupt?
In some cases, you can use application specific tricks. For example,
if a thread is waiting on a known socket, you can close the socket to
cause the thread to return immediately. Unfortunately, there really
isn't any technique that works in general. It should be noted that in
all situations where a waiting thread doesn't respond to
Thread.interrupt, it wouldn't respond to Thread.stop either. Such
cases include deliberate denial-of-service attacks, and I/O operations
for which thread.stop and thread.interrupt do not work properly.
底线:
确保所有线程都可以被中断,否则您需要特定的线程知识,比如设置一个标志。也许您可以要求将任务连同停止任务所需的代码一起提供给您——用
我刚刚为这个创建了一个助手类。作品很棒:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * TimeOut class - used for stopping a thread that is taking too long * @author Peter Goransson * */ public class TimeOut { Thread interrupter; Thread target; long timeout; boolean success; boolean forceStop; CyclicBarrier barrier; /** * * @param target The Runnable target to be executed * @param timeout The time in milliseconds before target will be interrupted or stopped * @param forceStop If true, will Thread.stop() this target instead of just interrupt() */ public TimeOut(Runnable target, long timeout, boolean forceStop) { this.timeout = timeout; this.forceStop = forceStop; this.target = new Thread(target); this.interrupter = new Thread(new Interrupter()); barrier = new CyclicBarrier(2); // There will always be just 2 threads waiting on this barrier } public boolean execute() throws InterruptedException { // Start target and interrupter target.start(); interrupter.start(); // Wait for target to finish or be interrupted by interrupter target.join(); interrupter.interrupt(); // stop the interrupter try { barrier.await(); // Need to wait on this barrier to make sure status is set } catch (BrokenBarrierException e) { // Something horrible happened, assume we failed success = false; } return success; // status is set in the Interrupter inner class } private class Interrupter implements Runnable { Interrupter() {} public void run() { try { Thread.sleep(timeout); // Wait for timeout period and then kill this target if (forceStop) { target.stop(); // Need to use stop instead of interrupt since we're trying to kill this thread } else { target.interrupt(); // Gracefully interrupt the waiting thread } System.out.println("done"); success = false; } catch (InterruptedException e) { success = true; } try { barrier.await(); // Need to wait on this barrier } catch (InterruptedException e) { // If the Child and Interrupter finish at the exact same millisecond we'll get here // In this weird case assume it failed success = false; } catch (BrokenBarrierException e) { // Something horrible happened, assume we failed success = false; } } } } |
它的名字是这样的:
1 2 3 4 5 6 7 8 9 10 11 | long timeout = 10000; // number of milliseconds before timeout TimeOut t = new TimeOut(new PhotoProcessor(filePath, params), timeout, true); try { boolean sucess = t.execute(); // Will return false if this times out if (!sucess) { // This thread timed out } else { // This thread ran completely and did not timeout } } catch (InterruptedException e) {} |
我认为您应该看看适当的并发处理机制(运行在无限循环中的线程本身听起来不太好,btw)。确保你读了一些关于"杀戮"或"停止"线程的主题。
你所描述的,听起来很像"集合",所以你可能想看看骑自行车的人。
可能还有其他的构造(例如使用countdownloatch)可以解决您的问题(一个线程等待闩锁超时,另一个线程在闩锁完成工作后应倒计时,这将在超时后或调用闩锁倒计时时释放第一个线程)。
我通常在这方面推荐两本书:实践中的Java并发编程和Java并发。
我给你发了一段代码,告诉你如何解决这个问题。举个例子,我正在读一份文件。您可以将此方法用于另一个操作,但需要实现kill()方法,以便中断主操作。
希望它有帮助
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * Main class * * @author el * */ public class Main { /** * Thread which perform the task which should be timed out. * * @author el * */ public static class MainThread extends Thread { /** * For example reading a file. File to read. */ final private File fileToRead; /** * InputStream from the file. */ final private InputStream myInputStream; /** * Thread for timeout. */ final private TimeOutThread timeOutThread; /** * true if the thread has not ended. */ boolean isRunning = true; /** * true if all tasks where done. */ boolean everythingDone = false; /** * if every thing could not be done, an {@link Exception} may have * Happens. */ Throwable endedWithException = null; /** * Constructor. * * @param file * @throws FileNotFoundException */ MainThread(File file) throws FileNotFoundException { setDaemon(false); fileToRead = file; // open the file stream. myInputStream = new FileInputStream(fileToRead); // Instantiate the timeout thread. timeOutThread = new TimeOutThread(10000, this); } /** * Used by the {@link TimeOutThread}. */ public void kill() { if (isRunning) { isRunning = false; if (myInputStream != null) { try { // close the stream, it may be the problem. myInputStream.close(); } catch (IOException e) { // Not interesting System.out.println(e.toString()); } } synchronized (this) { notify(); } } } /** * The task which should be timed out. */ @Override public void run() { timeOutThread.start(); int bytes = 0; try { // do something while (myInputStream.read() >= 0) { // may block the thread. myInputStream.read(); bytes++; // simulate a slow stream. synchronized (this) { wait(10); } } everythingDone = true; } catch (IOException e) { endedWithException = e; } catch (InterruptedException e) { endedWithException = e; } finally { timeOutThread.kill(); System.out.println("-->read" + bytes +" bytes."); isRunning = false; synchronized (this) { notifyAll(); } } } } /** * Timeout Thread. Kill the main task if necessary. * * @author el * */ public static class TimeOutThread extends Thread { final long timeout; final MainThread controlledObj; TimeOutThread(long timeout, MainThread controlledObj) { setDaemon(true); this.timeout = timeout; this.controlledObj = controlledObj; } boolean isRunning = true; /** * If we done need the {@link TimeOutThread} thread, we may kill it. */ public void kill() { isRunning = false; synchronized (this) { notify(); } } /** * */ @Override public void run() { long deltaT = 0l; try { long start = System.currentTimeMillis(); while (isRunning && deltaT < timeout) { synchronized (this) { wait(Math.max(100, timeout - deltaT)); } deltaT = System.currentTimeMillis() - start; } } catch (InterruptedException e) { // If the thread is interrupted, // you may not want to kill the main thread, // but probably yes. } finally { isRunning = false; } controlledObj.kill(); } } /** * Start the main task and wait for the end. * * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { long start = System.currentTimeMillis(); MainThread main = new MainThread(new File(args[0])); main.start(); try { while (main.isRunning) { synchronized (main) { main.wait(1000); } } long stop = System.currentTimeMillis(); if (main.everythingDone) System.out.println("all done in" + (stop - start) +" ms."); else { System.out.println("could not do everything in" + (stop - start) +" ms."); if (main.endedWithException != null) main.endedWithException.printStackTrace(); } } catch (InterruptedException e) { System.out.println("You've killed me!"); } } } |
当做
这是我真正使用的助手类运行或调用一段Java代码:
这是基于巴鲁斯克的完美答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | package com.mycompany.util.concurrent; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Calling {@link Callable#call()} or Running {@link Runnable#run()} code * with a timeout based on {@link Future#get(long, TimeUnit))} * @author pascaldalfarra * */ public class CallableHelper { private CallableHelper() { } public static final void run(final Runnable runnable, int timeoutInSeconds) { run(runnable, null, timeoutInSeconds); } public static final void run(final Runnable runnable, Runnable timeoutCallback, int timeoutInSeconds) { call(new Callable<Void>() { @Override public Void call() throws Exception { runnable.run(); return null; } }, timeoutCallback, timeoutInSeconds); } public static final <T> T call(final Callable<T> callable, int timeoutInSeconds) { return call(callable, null, timeoutInSeconds); } public static final <T> T call(final Callable<T> callable, Runnable timeoutCallback, int timeoutInSeconds) { ExecutorService executor = Executors.newSingleThreadExecutor(); try { Future<T> future = executor.submit(callable); T result = future.get(timeoutInSeconds, TimeUnit.SECONDS); System.out.println("CallableHelper - Finished!"); return result; } catch (TimeoutException e) { System.out.println("CallableHelper - TimeoutException!"); if(timeoutCallback != null) { timeoutCallback.run(); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { executor.shutdownNow(); executor = null; } return null; } } |
巴鲁斯克的回答很好:
但要补充的是,超时本身不会中断线程本身。即使您正在检查while(!thread.interrupted())在您的任务中。如果要确保线程已停止,还应确保在捕获超时异常时调用future.cancel()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.stackoverflow.q2275443; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class Test { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(new Task()); try { System.out.println("Started.."); System.out.println(future.get(3, TimeUnit.SECONDS)); System.out.println("Finished!"); } catch (TimeoutException e) { //Without the below cancel the thread will continue to live // even though the timeout exception thrown. future.cancel(); System.out.println("Terminated!"); } executor.shutdownNow(); } } class Task implements Callable<String> { @Override public String call() throws Exception { while(!Thread.currentThread.isInterrupted()){ System.out.println("Im still running baby!!"); } } } |
有一件事我没有提到,杀死线程通常是一个坏主意。有一些技术可以使线程方法完全中止,但这与在超时后终止线程不同。
你所建议的风险是,你可能不知道线程在你杀死它时处于什么状态,所以你有引入不稳定性的风险。更好的解决方案是确保线程代码不会自行挂起,或者会很好地响应中止请求。
下面的代码段将在单独的线程中启动一个操作,然后等待10秒钟以完成该操作。如果操作没有及时完成,代码将尝试取消该操作,然后继续其愉快的方式。即使操作不能轻易取消,父线程也不会等待子线程终止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ExecutorService executorService = getExecutorService(); Future<SomeClass> future = executorService.submit(new Callable<SomeClass>() { public SomeClass call() { // Perform long-running task, return result. The code should check // interrupt status regularly, to facilitate cancellation. } }); try { // Real life code should define the timeout as a constant or // retrieve it from configuration SomeClass result = future.get(10, TimeUnit.SECONDS); // Do something with the result } catch (TimeoutException e) { future.cancel(true); // Perform other error handling, e.g. logging, throwing an exception } |
在Balusc给出的解决方案中,主线程将在超时期间保持阻塞状态。如果有多个线程的线程池,您将需要与将来使用的相同数量的额外线程。get(long timeout,timeunit unit)blocking call等待线程超过超时时间,并关闭线程。
这个问题的一般解决方案是创建一个线程池执行器装饰器,它可以添加超时功能。这个decorator类应该创建尽可能多的线程,并且所有这些线程都应该只用于等待和关闭线程池执行器。
泛型类的实现方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import java.util.List; import java.util.concurrent.*; public class TimeoutThreadPoolDecorator extends ThreadPoolExecutor { private final ThreadPoolExecutor commandThreadpool; private final long timeout; private final TimeUnit unit; public TimeoutThreadPoolDecorator(ThreadPoolExecutor threadpool, long timeout, TimeUnit unit ){ super( threadpool.getCorePoolSize(), threadpool.getMaximumPoolSize(), threadpool.getKeepAliveTime(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, threadpool.getQueue()); this.commandThreadpool = threadpool; this.timeout=timeout; this.unit=unit; } @Override public void execute(Runnable command) { super.execute(() -> { Future<?> future = commandThreadpool.submit(command); try { future.get(timeout, unit); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException | TimeoutException e) { throw new RejectedExecutionException(e); } finally { future.cancel(true); } }); } @Override public void setCorePoolSize(int corePoolSize) { super.setCorePoolSize(corePoolSize); commandThreadpool.setCorePoolSize(corePoolSize); } @Override public void setThreadFactory(ThreadFactory threadFactory) { super.setThreadFactory(threadFactory); commandThreadpool.setThreadFactory(threadFactory); } @Override public void setMaximumPoolSize(int maximumPoolSize) { super.setMaximumPoolSize(maximumPoolSize); commandThreadpool.setMaximumPoolSize(maximumPoolSize); } @Override public void setKeepAliveTime(long time, TimeUnit unit) { super.setKeepAliveTime(time, unit); commandThreadpool.setKeepAliveTime(time, unit); } @Override public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { super.setRejectedExecutionHandler(handler); commandThreadpool.setRejectedExecutionHandler(handler); } @Override public List<Runnable> shutdownNow() { List<Runnable> taskList = super.shutdownNow(); taskList.addAll(commandThreadpool.shutdownNow()); return taskList; } @Override public void shutdown() { super.shutdown(); commandThreadpool.shutdown(); } } |
上面的装饰可以使用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args){ long timeout = 2000; ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(true)); threadPool = new TimeoutThreadPoolDecorator( threadPool , timeout, TimeUnit.MILLISECONDS); threadPool.execute(command(1000)); threadPool.execute(command(1500)); threadPool.execute(command(2100)); threadPool.execute(command(2001)); while(threadPool.getActiveCount()>0); threadPool.shutdown(); } private static Runnable command(int i) { return () -> { System.out.println("Running Thread:"+Thread.currentThread().getName()); System.out.println("Starting command with sleep:"+i); try { Thread.sleep(i); } catch (InterruptedException e) { System.out.println("Thread"+Thread.currentThread().getName()+" with sleep of"+i+" is Interrupted!!!"); return; } System.out.println("Completing Thread"+Thread.currentThread().getName()+" after sleep of"+i); }; } } |
我在寻找一个执行器服务,可以中断它执行的所有超时的可运行文件,但没有找到。几个小时后,我创建了一个如下。可以修改这个类以增强健壮性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class TimedExecutorService extends ThreadPoolExecutor { long timeout; public TimedExecutorService(int numThreads, long timeout, TimeUnit unit) { super(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(numThreads + 1)); this.timeout = unit.toMillis(timeout); } @Override protected void beforeExecute(Thread thread, Runnable runnable) { Thread interruptionThread = new Thread(new Runnable() { @Override public void run() { try { // Wait until timeout and interrupt this thread Thread.sleep(timeout); System.out.println("The runnable times out."); thread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }); interruptionThread.start(); } } |
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public static void main(String[] args) { Runnable abcdRunnable = new Runnable() { @Override public void run() { System.out.println("abcdRunnable started"); try { Thread.sleep(20000); } catch (InterruptedException e) { // logger.info("The runnable times out."); } System.out.println("abcdRunnable ended"); } }; Runnable xyzwRunnable = new Runnable() { @Override public void run() { System.out.println("xyzwRunnable started"); try { Thread.sleep(20000); } catch (InterruptedException e) { // logger.info("The runnable times out."); } System.out.println("xyzwRunnable ended"); } }; int numThreads = 2, timeout = 5; ExecutorService timedExecutor = new TimedExecutorService(numThreads, timeout, TimeUnit.SECONDS); timedExecutor.execute(abcdRunnable); timedExecutor.execute(xyzwRunnable); timedExecutor.shutdown(); } |
我认为答案主要取决于任务本身。
- 它是在一遍又一遍地做一项任务吗?
- 超时是否有必要在当前正在运行的任务过期后立即中断它?
如果第一个答案是"是",而第二个答案是"否",您可以这样简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public class Main { private static final class TimeoutTask extends Thread { private final long _timeoutMs; private Runnable _runnable; private TimeoutTask(long timeoutMs, Runnable runnable) { _timeoutMs = timeoutMs; _runnable = runnable; } @Override public void run() { long start = System.currentTimeMillis(); while (System.currentTimeMillis() < (start + _timeoutMs)) { _runnable.run(); } System.out.println("execution took" + (System.currentTimeMillis() - start) +" ms"); } } public static void main(String[] args) throws Exception { new TimeoutTask(2000L, new Runnable() { @Override public void run() { System.out.println("doing something ..."); try { // pretend it's taking somewhat longer than it really does Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } }).start(); } } |
如果这不是一个选项,请缩小您的需求-或显示一些代码。
现在,我遇到了这样的问题。它碰巧解码了图片。解码过程花费的时间太多,屏幕无法正常显示。l添加一个时间控制器:当时间太长时,从当前线程弹出。以下是差异:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Bitmap> future = executor.submit(new Callable<Bitmap>() { @Override public Bitmap call() throws Exception { Bitmap bitmap = decodeAndScaleBitmapFromStream(context, inputUri);// do some time consuming operation return null; } }); try { Bitmap result = future.get(1, TimeUnit.SECONDS); } catch (TimeoutException e){ future.cancel(true); } executor.shutdown(); return (bitmap!= null); |
我也有同样的问题。所以我想出了一个简单的解决办法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public class TimeoutBlock { private final long timeoutMilliSeconds; private long timeoutInteval=100; public TimeoutBlock(long timeoutMilliSeconds){ this.timeoutMilliSeconds=timeoutMilliSeconds; } public void addBlock(Runnable runnable) throws Throwable{ long collectIntervals=0; Thread timeoutWorker=new Thread(runnable); timeoutWorker.start(); do{ if(collectIntervals>=this.timeoutMilliSeconds){ timeoutWorker.stop(); throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In"+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated."); } collectIntervals+=timeoutInteval; Thread.sleep(timeoutInteval); }while(timeoutWorker.isAlive()); System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within"+collectIntervals+" Milli Seconds."); } /** * @return the timeoutInteval */ public long getTimeoutInteval() { return timeoutInteval; } /** * @param timeoutInteval the timeoutInteval to set */ public void setTimeoutInteval(long timeoutInteval) { this.timeoutInteval = timeoutInteval; } } |
保证if块没有在时间限制内执行。进程将终止并引发异常。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | try { TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds Runnable block=new Runnable() { @Override public void run() { //TO DO write block of code } }; timeoutBlock.addBlock(block);// execute the runnable block } catch (Throwable e) { //catch the exception here . Which is block didn't execute within the time limit } |