![](/img/trans.png)
[英]ExecutorService - Killing thread after some specified time limit
[英]Killing thread after some specified time limit in Java
有沒有辦法在Java中指定的時間限制后殺死子線程? 編輯:此特定線程也可能在最壞的情況下被阻止(線程用於等待文件修改並阻塞直到發生此事件),所以我不確定interrupt()是否會成功?
使用ExecutorService
執行Callable
,檢查可以指定超時的方法。 例如
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes.
executor.shutdown();
這里的Task
當然是實現了Callable
。
為什么不在特定時間后interrupt()
它? 您生成的線程必須能夠正確處理InterruptedException
。
有關干凈地關閉線程的更多信息,請參閱此文章( http://www.javaspecialists.eu/archive/Issue056.html )。
另請參見Executor / Future框架,它提供了在特定時間限制內收集結果和/或終止線程的有用方法。
不直接; 我認為最簡單的方法是使用該時間限制在該線程上加入(),如果在連接結束時沒有完成,則中斷該線程。
所以,
Thread t = ...
t.join(timelimit);
if (t.isAlive()) t.interrupt();
注意我使用了中斷而不是實際殺死它,它更安全。 我還建議使用執行程序而不是直接操作線程。
自Java 9以來,在CompletableFuture
作為JEP 266的一部分引入了一些有用的更改。使用orTimeout方法,現在可以像下面這樣編寫它:
CompletableFuture.runAsync(thread::run)
.orTimeout(30, TimeUnit.SECONDS)
.exceptionally(throwable -> {
log.error("An error occurred", throwable);
return null;
});
不幸的是,在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));
}
}
當然,上面的代碼很容易被重寫為一個靜態的工廠方法:
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);
}
您可以從jcabi-aspects (我是開發人員)為您的方法使用AOP和@Timeable
注釋:
@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
// do something time consuming
}
當達到時間限制時,您的線程將被interrupted()
標志設置為true
,您的工作就是正確處理這種情況並停止執行。 通常它由Thread.sleep(..)
。
對於與Thread
的API文檔相關聯的原因,殺死線程通常是一個壞主意。
如果你死定了,請使用一個全新的過程。
否則通常的事情是讓線程輪詢System.nanoTime
,輪詢一個(可能的volatile
)標志,排隊“毒丸”或那種性質的東西。
布賴恩是對的,打斷它比“停止”線程更安全。
如果線程在中間修改時鎖定對象並突然停止(導致鎖被釋放)怎么辦? 你得到奇怪的結果。
不要使用destroy()
因為它不執行任何清理。
最直接的方法是使用join()
,就像
try {
thread.join();
} catch (InterruptedException e) {//log exception...}
您可以使用ExecutorService
。 如果你有幾個並發運行的線程,這將是很有意義的。 如果您需要在其他線程運行時生成新線程,則可以將其與BlockingQueue
結合使用。
ThreadPoolExecutor
( ExecutorService
-implementation)可以將BlockingQueue
作為參數,您只需將新線程添加到隊列中即可。 完成后,您只需終止ThreadPoolExecutor
。
private BlockingQueue<Runnable> queue;
...
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000),
TimeUnit.MILLISECONDS, this.queue);
您可以保留添加到隊列中的所有線程的計數。 當你認為你已經完成時(隊列是空的,或許?)只需將其與之比較即可
if (issuedThreads == pool.getCompletedTaskCount()) {
pool.shutdown();
}
如果兩者匹配,你就完成了。 終止池的另一種方法是在循環中等待一秒:
try {
while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {//log exception...}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.