未来取消不起作用

2022-09-03 13:54:17

我有一个漂亮而紧凑的代码,它没有像我预期的那样工作。

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");

    }

}

输出为:

超时为真

结束

问:为什么不终止 future.cancel(true) 方法,即名为 Runnable 的方法?程序将“END”写入输出后,“r”Runnable仍在运行。


答案 1

问题在于你的Runnable是不可中断的:任务中断是Java中的一个协作过程,取消的代码需要定期检查它是否被取消,否则它不会响应中断。

您可以按如下方式修改代码,并且它应该按预期工作:

Runnable r = new Runnable() {
    @Override public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {}
        } finally {
            System.out.println("FINALLY");
        }
    }
};

答案 2

这总是有点误导:ExceutorService甚至底层线程调度器都不知道Runnable在做什么。在你的情况下,他们不知道有一个无条件的循环。

所有这些方法(取消、完成等)都与管理执行器结构中的线程相关。 从执行程序服务的角度取消线程。cancel

程序员必须测试 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");

}

}


推荐