我有以下代码:
public class Cancelling {
public static void main(String args[]) {
ToBeCancelled tbc = new ToBeCancelled();
ForkJoinPool pool = new ForkJoinPool(1);
Future<?> future = pool.submit(tbc);
try {
Thread.sleep(3000);
} catch (InterruptedException ie) {}
future.cancel(true);
if (future.isCancelled())
System.out.println("The task has been cancelled");
}
}
ToBeCancelled
类为:
public class ToBeCancelled implements Runnable {
public void run() {
try {
Thread.sleep(5000); // should throw exception here
} catch (Exception e) {
return; // should exit
}
System.out.println("I should never be able to print this");
}
}
主线程应启动,等待 3 秒,然后使用 future.cancel(true)
取消 ToBeCancelled
任务。然后它应该打印任务已被取消
,而任务永远不会打印其消息。
至少,这是我从控制台启动它时发生的情况。
当我从带有输出重定向到的 TextArea 的 GUI 应用程序启动它时,情况并非如此。 main 方法确实打印 任务已取消
,但任务还打印 我应该永远无法打印此
。
这让我发疯。据我了解,任务应该在使用 Thread.sleep(5000) 方法时接收其取消命令,这将引发异常,该异常随后被捕获并使线程返回。但它并没有发生,但主要认为它已经被取消了。就像任务完全忽略 cancel
方法一样。
我已经尝试了我能想到的一切,检查 cancel
的返回值,使用 Thread.currentThread().isInterrupted()
让任务等待更长时间,但没有任何效果。
我觉得我错过了一些非常简单的东西,但我就是找不到它是什么。有什么想法吗?
如果有人认为这可能是 GUI 应用程序上的问题,这是启动程序的方法:
public static void StartProgram(String name) {
try {
Method m = Class.forName(name).getDeclaredMethod("main",String[].class);
Object[] args = new Object[1];
String s[] = new String[2];
s[0] = tf1.getText();
s[1] = tf2.getText();
args[0] = s;
t = new Thread(new ProgramStarter(args, m));
t.start();
} catch (Exception e) {
e.printStackTrace();
}
}
ProgramStarter
为:
public class ProgramStarter implements Runnable {
private Object[] args;
private Method m;
public ProgramStarter(Object args[], Method m) {
this.args = args;
this.m = m;
}
public void run() {
try {
m.invoke(null, args);
} catch (Exception e) {
e.printStackTrace();
}
}
}
最佳答案
问题是您的验证错误。您认为您的代码在从控制台运行时可以正常工作,但事实上,它在所有情况下都会失败。当从控制台运行时,您的主线程在尝试取消 future 后结束,并且 JVM 将终止,因为 JVM 中只剩下守护线程。由于 JVM 终止,您不会注意到取消不起作用。
当在 main
方法末尾添加 sleep
来延迟 JVM 终止时,您会注意到从控制台运行时也会打印 “I should never be able to print this”
。因此,GUI 和控制台版本之间的唯一区别是正在运行的事件调度线程会阻止 JVM 终止,因此您会看到它不起作用。
底线是:不要使用 ForkJoinPool
除非你有理由这样做。
由于您只想提交
到一个简单的单后台线程执行器,因此可以使用Executors.newFixedThreadPool(1)
创建执行器。这具有较少的意外行为:默认情况下,它的线程是非守护进程,并且它的 Future
将按预期中断取消
。
关于java - Future cancel(boolean b) 方法在 GUI 应用程序中使用时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23723855/