![](/img/trans.png)
[英]Using Callable and ExecutorCompletionService, future.cancel() does not work
[英]future.cancel does not work
我有一個漂亮而緊湊的代碼,它不像我預期的那樣工作。
public class Test {
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
try {
for (;;) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
輸出是:
超時真
結尾
問題:為什么不終止被調用的 Runnable 的 future.cancel(true) 方法? 程序將“END”寫入輸出后,“r”Runnable 仍在運行。
問題是你的 Runnable 是不可中斷的:任務中斷是 Java 中的一個協作過程,被取消的代碼需要定期檢查它是否被取消,否則它不會響應中斷。
您可以按如下方式修改代碼,它應該可以按預期工作:
Runnable r = new Runnable() {
@Override public void run() {
try {
while (!Thread.currentThread.isInterrupted()) {}
} finally {
System.out.println("FINALLY");
}
}
};
這總是有點誤導:ExceutorService 甚至底層線程調度程序對 Runnable 正在做什么一無所知。 在您的情況下,他們不知道存在無條件循環。
所有這些方法(cancel、done、...)都與在 Executor 結構中管理 Threads 相關。 cancel
從 Executor 服務的角度取消線程。
程序員必須測試 Runnable 是否被取消並且必須終止run()
方法。
所以在你的情況下(如果我沒記錯的話)是這樣的:
public class Test {
public static void main(String[] args) {
FutureTask r = new FutureTask () {
@Override
public void run() {
try {
for (;!isCancelled();) {
}
} finally {
System.out.println("FINALLY");
}
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(r);
try {
future.get(3, TimeUnit.SECONDS);
} catch (TimeoutException e) {
boolean c = future.cancel(true);
System.out.println("Timeout " + c);
} catch (InterruptedException | ExecutionException e) {
System.out.println("interrupted");
}
System.out.println("END");
}
}
當您取消Runnable
已經開始的Future
,將在運行Runnable
的Thread
上調用interrupt
方法。 但這不一定會停止線程。 事實上,如果它被困在一個緊密的循環中,就像你在這里看到的那樣, Thread
不會停止。 在這種情況下, interrupt
方法只是設置一個稱為“中斷狀態”的標志,它告訴線程在可以時停止。
Future.cancel()將取消任何排隊的任務,或者如果您的線程已經運行,則會在您的線程上調用Thread.interrupt() 。
你需要中斷你的代碼
您的代碼有責任為任何中斷做好准備。 我想說的是,每當你有一個長時間運行的任務時,你就插入一些像這樣的中斷就緒代碼:
while (... something long...) {
... do something long
if (Thread.interrupted()) {
... stop doing what I'm doing...
}
}
如何停止我正在做的事情?
您有多種選擇:
private void someMethodDeepDown() {
while (.. long running task .. ) {
... do lots of work ...
if (Thread.interrupted()) {
// oh no! an interrupt!
Thread.currentThread().interrupt();
throw new SomeOtherException();
}
}
}
現在異常可以傳播或終止線程或被捕獲,但接收代碼有望注意到中斷正在進行中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.