将来取消(布尔b)方法在GUI应用程序中使用时不起作用

时间:2014-05-18 15:51:51

标签: java multithreading user-interface future

我有以下代码:

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秒,然后使用ToBeCancelled取消future.cancel(true)任务。然后它应该打印The task has been cancelled,而任务永远不会打印它的消息。 至少,当我从控制台启动它时会发生这种情况。

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

这让我疯了。根据我的理解,任务应该在cancel方法上接收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();
    }
}
}

1 个答案:

答案 0 :(得分:1)

问题是您的验证错误。您认为您的代码在从控制台运行时有效,但事实上,它在所有情况下都会失败。从控制台运行时,主线程在尝试取消未来后结束,JVM将终止,因为JVM中只剩下守护程序线程。由于JVM终止,您没有注意到取消不起作用。

sleep方法的末尾添加main以延迟JVM终止时,您会注意到从控制台运行时也会打印"I should never be able to print this"。因此,GUI和控制台版本之间的唯一区别是运行的事件调度线程阻止JVM终止,因此您发现它不起作用。


底线是:不要使用 ForkJoinPool ,除非您有理由

由于您只需要submit到一个简单的单背景线程执行程序,您可以使用Executors.newFixedThreadPool(1)创建执行程序。这意外行为较少:默认情况下,它的线程是非守护进程,而Futurecancel按预期中断。