我有一个很好的紧凑的代码,但没有像我预期的那样工作。
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");
}
}
输出是:
超时true
结束
问题:为什么调用Runnable的future.cancel(true)方法不终止呢?
问题是你的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结构中的线程有关。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");
}
}
当您取消一个 Future
其 Runnable
已经开始, interrupt
方法是在 Thread
正在运行的 Runnable
. 但这不一定能让线程停止。 事实上,如果它被卡在一个紧密的圈里,就像你这里的这个, Thread
不会停止。 在这种情况下 interrupt
方法只是设置了一个名为 "中断状态 "的标志,它告诉线程在可以停止的时候停止。
Future.cancel() 将取消任何排队的任务,或者调用 线程.中断() 如果您的线程已经在运行,您需要中断您的代码。
你需要中断你的代码
你的代码的责任是为任何中断做好准备。我想说的是,每当你有一个长期运行的任务时,你都要插入一些像这样的中断准备代码。
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();
}
}
}
现在异常可以传播,要么终止线程,要么被捕获, 但希望接收代码能注意到中断正在进行中。