Future cancel(boolean b)方法在GUI应用程序中使用时不起作用



我有以下代码:

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任务。然后,它应该打印The task has been cancelled,而任务永远不会打印它的消息。至少,当我从控制台启动它时是这样的。

当我从带有TextArea的GUI应用程序启动它时(输出被重定向到TextArea),情况并非如此。主方法打印The task has been cancelled,但任务也打印I should never be able to print this

这快把我逼疯了。根据我的理解,任务应该在Thread.sleep(5000)方法上接收其cancel命令,这将触发一个异常,从而捕获并使线程返回。但这并没有发生,而且主要认为它已经被取消了。这就像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 ,除非你有这样做的理由

因为您只想让submit成为一个简单的单后台线程执行器,所以您可以使用Executors.newFixedThreadPool(1)创建执行器。这有更少的意外行为:默认情况下,它的线程是非守护进程,它的Futurecancel与中断预期。

相关内容

  • 没有找到相关文章

最新更新