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

标签 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 秒,然后使用 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/

相关文章:

java - 使用 Java 解析特定元素的 XML

java - 暂停并执行JSP文件

java - 安卓编码 "Simon";很难暂停代码

Python3——突破包罗万象的 try block

java - 显示扩展 JScrollPane 的类

user-interface - 窗口与离屏窗口

iphone - 关于创建 iPhone Piano UI 的问题

java - 使用 Scanner 时出现 NoSuchElementException

c - 多线程二维数组输入无法在 C 中使用 pthreads 产生输出

Swift COW 线程安全