![](/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.