Future.cancel()疑难杂症

问题描述

在学习并发编程的时候对Future的cancel有点小疑惑。
future类里面,有cancel()和isCanceled()的两个方法,前者是发送取消命令给线程并返回是否发送成功,后者是判断该线程是否被取消。但是在实际运用时出现了一些问题。以下会列出问题:

问题出现的环境背景及自己尝试过哪些方法

查阅了《java并发编程》,发现书里对isCanceled没有详细介绍

相关代码

问题
1.我对线程发送了cancel命令,但没有用isInterrupted来截获cancel命令,也就是说,线程还能一直执行下去。为什么isCanceled()返回了true呢?

public class Test10 {


    class MyCallable implements Callable<String> {


        @Override
        public String call() throws Exception {

            int i = 0;
            while (i == 0) {
                System.out.println("z");

            }
            return "always run";
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Test10 test10 = new Test10();
        MyCallable myCallable = test10.new MyCallable();
        ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());

        Future<String> future = executorService.submit(myCallable);
        Thread.sleep(4000);
        System.out.println(future.cancel(true) + " " + future.isCancelled());

    }
}

这个是返回结果:
clipboard.png

2.当我对sleep的线程发出cancel命令,会发生什么呢?我试了下好像会一直处于sleep状态了

public class Test10 {


    class MyCallable implements Callable<String> {


        @Override
        public String call() throws Exception {

            int i = 0;
            while (i == 0) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("截获中断");
                }
                Thread.sleep(1000);
                System.out.println("z");

            }
            return "always run";
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Test10 test10 = new Test10();
        MyCallable myCallable = test10.new MyCallable();
        ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        Future<String> future = executorService.submit(myCallable);
        Thread.sleep(4000);
        System.out.println(future.cancel(true) + " " + future.isCancelled());
    }
}

这个是返回结果:

clipboard.png

你期待的结果是什么?实际看到的错误信息又是什么?

希望有大牛解惑,另外可以推荐一些并发编程的书吗?我看了《java并发编程:核心方法与框架》以及《java并发编程实战》了,总感觉学的比较浅。

阅读 9.1k
2 个回答

Future 的状态与对应线程的状态是分开的,取消状态的 Future 仅仅代表它自己的状态为已取消,与线程状态无关。
一般来说,使用 Future 来实现异步操作的时候,都建议线程要响应 Future 的状态变更。但是这一条并不是强制的,所以就会出现你的问题中的情况,Future 已经取消了,但线程却并没有响应。

把第一段代码的 i == 0 换成 !Thread.currentThread().isInterrupted() 就行了

  1. 中断只是中断,不是停掉线程,中断了之后可以获取到isInterrupted == true(一般情况)或者捕获到InterruptedException(比如中断时正在sleep()
  2. 第二段代码,异常信息被吞掉,线程池没关,所以不退出,不是一直sleep
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题