我有一个漂亮而紧凑的代码,它不能像我预期的那样工作。
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");
}
}
输出结果为:
超时
END
问题: 为什么不终止future.cancel(true)方法调用Runnable? 程序将“END”写入输出后,“r”Runnable仍在运行。
答案 0 :(得分:8)
问题在于您的Runnable不可中断:任务中断是Java中的协作过程,取消的代码需要定期检查是否已被取消,否则它将不会响应中断。
您可以按如下方式修改代码,它应该按预期工作:
Runnable r = new Runnable() {
@Override public void run() {
try {
while (!Thread.currentThread.isInterrupted()) {}
} finally {
System.out.println("FINALLY");
}
}
};
答案 1 :(得分:3)
这总是有点误导:ExceutorService甚至底层线程调度程序都不知道Runnable正在做什么。在你的情况下,他们不知道有一个无条件的循环。
所有这些方法(取消,完成,......)都与Executor结构中的管理线程有关。 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");
}
}
答案 2 :(得分:1)
当您取消Future
已经开始的Runnable
时,interrupt
方法会在Thread
上运行Runnable
。但这并不一定会阻止这个问题。事实上,如果它被困在一个紧密的循环中,就像你在这里的那个,Thread
不会停止。在这种情况下,interrupt
方法只设置一个名为&#34;中断状态&#34;的标志,它告诉线程何时停止。
答案 3 :(得分:1)
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();
}
}
}
现在,异常可以传播终止线程或被捕获的异常,但是接收代码有望注意到正在进行中断。