在 Java 中的某个指定时间限制后杀死线程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2733356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Killing thread after some specified time limit in Java
提问by Traker
Is there a way to kill a child thread after some specified time limit in Java? Edit: Also this particular thread may be blocked in its worst case (Thread is used to wait for a file modification and blocks until this event occurs), so im not sure that interrupt() will be successful?
有没有办法在 Java 中的某个指定时间限制后杀死子线程?编辑:这个特定的线程也可能在最坏的情况下被阻塞(线程用于等待文件修改并阻塞直到发生此事件),所以我不确定中断()会成功吗?
采纳答案by BalusC
Make use of ExecutorService
to execute the Callable
, checkout the methods wherein you can specify the timeout. E.g.
利用ExecutorService
执行Callable
, checkout 可以指定超时的方法。例如
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes.
executor.shutdown();
Here Task
of course implements Callable
.
这里Task
当然实现了Callable
.
回答by Brian Agnew
Why not interrupt()
it after a particular time ? Your spawned thread will have to be able to handle an InterruptedException
properly.
为什么不在interrupt()
特定时间之后呢?您生成的线程必须能够InterruptedException
正确处理。
See this article (http://www.javaspecialists.eu/archive/Issue056.html) for more information on shutting down threads cleanly.
请参阅这篇文章 ( http://www.javaspecialists.eu/archive/Issue056.html),了解有关彻底关闭线程的更多信息。
See also the Executor/Future framework, which provide useful methods for collecting results and/or terminating threads within particular time limits.
另请参阅 Executor/Future 框架,它提供了在特定时间限制内收集结果和/或终止线程的有用方法。
回答by Tom Hawtin - tackline
Killing a thread is generally a bad idea for reasons linked to for the API docs for Thread
.
杀死一个线程通常是一个坏主意,原因与Thread
.
If you are dead set on killing, use a whole new process.
如果您一心想杀人,请使用全新的流程。
Otherwise the usual thing is to have the thread poll System.nanoTime
, poll a (possible volatile
) flag, queue a "poison pill" or something of that nature.
否则通常的事情是让线程轮询System.nanoTime
,轮询(可能的volatile
)标志,排队“毒丸”或类似性质的东西。
回答by Ryan P.
Brian's right, interrupting it is safer than "stopping" the thread.
What if the thread is locking on an object mid-modification, and suddenly gets stopped (which causes the lock to be released)? You get weird results.
Brian 是对的,中断它比“停止”线程更安全。
如果线程在修改中锁定对象,并且突然停止(导致锁定被释放)怎么办?你会得到奇怪的结果。
回答by Oak
Not directly; I think the simplest way is to join() on that thread with that time limit, and interrupt the thread if it's not done by the time the join ended.
不直接;我认为最简单的方法是在具有该时间限制的线程上 join() ,如果在连接结束时还没有完成,则中断线程。
So,
所以,
Thread t = ...
t.join(timelimit);
if (t.isAlive()) t.interrupt();
Notice I used interrupt instead of actually killing it, it's much safer. I would also recommend using executors instead of directly manipulating threads.
注意我使用了中断而不是实际杀死它,它更安全。我还建议使用执行程序而不是直接操作线程。
回答by Lars Andren
Do not use destroy()
since that does not perform any cleanup.
不要使用,destroy()
因为它不会执行任何清理。
The most straightforward way is to use join()
, like
最直接的方法是使用join()
,比如
try {
thread.join();
} catch (InterruptedException e) {//log exception...}
You could use an ExecutorService
. That would make a lot of sense if you have several threads running concurrently. If you have the need to spawn new threads while other threads are running, you can combine this with a BlockingQueue
.
你可以使用一个ExecutorService
. 如果您有多个线程同时运行,这将很有意义。如果您需要在其他线程运行时生成新线程,您可以将其与BlockingQueue
.
A ThreadPoolExecutor
(an ExecutorService
-implementation) can take a BlockingQueue
as argument, and you can simply add new threads to the queue. When you are done you simply terminate the ThreadPoolExecutor
.
A ThreadPoolExecutor
(an ExecutorService
-implementation) 可以将 aBlockingQueue
作为参数,您可以简单地将新线程添加到队列中。完成后,您只需终止ThreadPoolExecutor
.
private BlockingQueue<Runnable> queue;
...
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000),
TimeUnit.MILLISECONDS, this.queue);
You can keep a count of all the threads added to the queue. When you think you are done (the queue is empty, perhaps?) simply compare this to
您可以对添加到队列中的所有线程进行计数。当你认为你完成了(队列是空的,也许?)只需将它与
if (issuedThreads == pool.getCompletedTaskCount()) {
pool.shutdown();
}
If the two match, you are done. Another way to terminate the pool is to wait a second in a loop:
如果两者匹配,您就完成了。终止池的另一种方法是在循环中等待一秒钟:
try {
while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {//log exception...}
回答by yegor256
You can use AOP and a @Timeable
annotation for your method from jcabi-aspects(I'm a developer):
您可以@Timeable
从jcabi-aspects(我是开发人员)为您的方法使用 AOP 和注释:
@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
// do something time consuming
}
When time limit is reached your thread will get interrupted()
flag set to true
and it's your job to handle this situation correctly and to stop execution. Normally it's done by Thread.sleep(..)
.
当达到时间限制时,您的线程将被interrupted()
设置为标志,true
您的工作是正确处理这种情况并停止执行。通常由Thread.sleep(..)
.
回答by ytterrr
Some helpful changes were introduced as part of JEP 266in CompletableFuture
since Java 9. Using orTimeoutmethod, for now, it is possible to write it like:
一些有用的变化是引入的一部分JEP 266在CompletableFuture
从Java 9.使用orTimeout方法,现在,就可以直接写成:
CompletableFuture.runAsync(thread::run)
.orTimeout(30, TimeUnit.SECONDS)
.exceptionally(throwable -> {
log.error("An error occurred", throwable);
return null;
});
In Java 8, unfortunately, you should use some extra code. Here is an example of delegation pattern usage with help of Lombok:
不幸的是,在 Java 8 中,您应该使用一些额外的代码。以下是在Lombok 的帮助下使用委托模式的示例:
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.TimeoutException;
import static lombok.AccessLevel.PRIVATE;
import lombok.AllArgsConstructor;
import lombok.experimental.Delegate;
@AllArgsConstructor(access = PRIVATE)
public class TimeoutableCompletableFuture<T> extends CompletableFuture<T> {
public static TimeoutableCompletableFuture<Void> runAsync(
Runnable runnable) {
return new TimeoutableCompletableFuture<>(
CompletableFuture.runAsync(runnable));
}
@Delegate
private final CompletableFuture<T> baseFuture;
public TimeoutableCompletableFuture<T> orTimeout(Duration duration) {
final CompletableFuture<T> otherFuture = new CompletableFuture<>();
Executors.newScheduledThreadPool(
1,
new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("timeoutable-%d")
.build())
.schedule(() -> {
TimeoutException ex = new TimeoutException(
"Timeout after " + duration);
return otherFuture.completeExceptionally(ex);
}, duration.toMillis(), MILLISECONDS);
return new TimeoutableCompletableFuture<>(
baseFuture.applyToEither(otherFuture, a -> a));
}
}
Of course, the code above easily could be rewritten as just a static factory method:
当然,上面的代码可以很容易地重写为静态工厂方法:
public static CompletableFuture<Void> runAsyncOrTimeout(
Runnable runnable, long timeout, TimeUnit unit) {
CompletableFuture<Void> other = new CompletableFuture<>();
Executors.newScheduledThreadPool(
1,
new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("timeoutafter-%d")
.build())
.schedule(() -> {
TimeoutException ex = new TimeoutException(
"Timeout after " + timeout);
return other.completeExceptionally(ex);
}, timeout, unit);
return CompletableFuture.runAsync(runnable).applyToEither(other, a -> a);
}