获取子线程的执行结果

  1. Runnable,不能返回一个返回值,不会抛出异常
  2. Callable,类似Runnable,但他可以返回一个返回值,也可以抛出异常

1、Future

  1. Future,可以用Future.get()接收Callable返回的线程执行结果
  2. Future,可以通过Future.isDone()来判断任务是否已经执行完了,以及取消这个任务,限时获取任务的结果等
  3. Future,在Callable的call()方法执行完毕之前,调用get()的线程(假设此时是主线程)会被阻塞,直到call()方法返回了结果后,此时future.get()才会得到该结果,然后主线程才会钱换到runnable(运行中)状态
  4. 所以Future是一个存储器,他存储了call()这个任物的结果,而这个任务的执行时间是无法提前确定的,因为这完全取决于call()方法执行的情况

(1)get()方法:获取结果

get方法的行为取决于Callable任务的状态,只有以下这5钟情况:

  1. 任务正常完成:get方法会立刻返回结果
  2. 任务尚未完成(任务还没开始或进行中):get将阻塞并直到任务完成
  3. 任务执行过程中抛出异常get方法会抛出ExecutionException(这里的抛出异常,是call()执行时产生的那个异常),get方法抛出的异常类型都是他
  4. 任务被取消:get方法会抛出CancellationException
  5. 任务超时:get方法有一个重载方法,是传入一个延迟时间的,如果时间到了还没有获得结果,get方法会抛出TimeoutException

(2)get(long timeout, TimeUnit unit):有超时的获取

  1. get(long timeout, TimeUnit unit):如果call()在规定时间内完成任务,那么就会正常获取到返回值;而如果再指定时间内没有计算出结果,那么就会抛出TimeoutException
  2. 超时不获取,任务需要取消

(3)cancel方法:取消任务的执行

(4)isDone()方法:判断线程是否执行完毕

  1. 执行完毕不代表成功执行
  2. 比如说任务执行失败,但是也是任务执行完毕,会返回ture
  3. 比如说任务被中断了,也会返回true

(5)isCancelled()方法:判断是否被取消

 

演示

1、Future

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
     //提交任务 Future<Integer> submit = executorService.submit(new CallableTesk());
     //阻塞获取结果 Integer integer = submit.get(); System.out.println("integer = " + integer); executorService.shutdown(); } static class CallableTesk implements Callable<Integer> { @Override public Integer call() throws Exception { Thread.sleep(1000); return new Random().nextInt(); } } }

优化

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        Callable<Integer> callable = ()->{
            Thread.sleep(1000);
            return new Random().nextInt();
        };
        //提交任务
        Future<Integer> submit = executorService.submit(callable);
        //获取结果(阻塞)
        Integer integer = submit.get();
        System.out.println("integer = " + integer);
        executorService.shutdown();
    }
}

 

 

2、批量接收结果

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        //创建结果集合
        List<Future> list = new ArrayList<>();

        //提交任务
        for (int i = 0; i < 10; i++) {
            //提交任务
            Future<Integer> submit = executorService.submit(new CallableTesk());
            //加入结果集合
            list.add(submit);
        }

        //获取结果
        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i).get();
            System.out.println(o);
        }
        executorService.shutdown();
    }


    static class CallableTesk implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);

            return new Random().nextInt();
        }
    }
}

 

3、执行异常和isDone

描述:演示get方法过程中抛出的异常,并不是一产生异常就抛出,而是直到执行get时,才会抛出。

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //提交任务
        Future<Integer> submit = executorService.submit(new CallableTesk());

        Thread.sleep(500);
        //判断任务是否执行完毕
        System.out.println("submit.isDone() = " + submit.isDone());
        //获取结果
        submit.get();
        executorService.shutdown();
    }


    static class CallableTesk implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            throw new RuntimeException("抛出异常");
        }
    }
}

 

4、默认广告的超时和取消

描述:演示get的超时方法,需要注意超时后处理,调用future.cancel()。演示cancel传入true和false的区别,代表是否中断正在执行的任务。

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //提交任务
        Future<Integer> submit = executorService.submit(new CallableTesk());


        //获取结果
        try {
            submit.get(1000, TimeUnit.MICROSECONDS);
        } catch (TimeoutException e) {
            //超时,终止任务
            submit.cancel(true);
            System.out.println("抛出TimeoutException");
        } catch (ExecutionException ee) {
            System.out.println("抛出ExecutionException");
        } catch (InterruptedException ie) {
            System.out.println("抛出InterruptedException");
        }
        executorService.shutdown();
    }


    static class CallableTesk implements Callable<Integer> {

        @Override
        public Integer call() {
            try {
                Thread.sleep(3000);
                System.out.println("进来了");
                return 1;
            } catch (InterruptedException e) {
                System.out.println("抛出InterruptedException");
                return 1;
            }
        }
    }
}

 

结果

 

 

把cancel参数改为false

public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //提交任务
        Future<Integer> submit = executorService.submit(new CallableTesk());


        //获取结果
        try {
            submit.get(1000, TimeUnit.MICROSECONDS);
        } catch (TimeoutException e) {
            //超时,终止任务
            submit.cancel(false);
            System.out.println("抛出TimeoutException");
        } catch (ExecutionException ee) {
            System.out.println("抛出ExecutionException");
        } catch (InterruptedException ie) {
            System.out.println("抛出InterruptedException");
        }
        executorService.shutdown();
    }


    static class CallableTesk implements Callable<Integer> {

        @Override
        public Integer call() {
            try {
                Thread.sleep(3000);
                System.out.println("进来了");
                return 1;
            } catch (InterruptedException e) {
                System.out.println("抛出InterruptedException");
                return 1;
            }
        }
    }
}

 

结果

 

说明cancel参数为true时,会终止线程,而false,还会继续执行线程任务。

 

 

 

5、cancel方法:取消任务的执行

(1)如果这个任务还没有开始执行,那么这种情况最简单,任务会被正常的取消,未来也不会被执行,方法返回true。

(2)如果任务已完成,或者已取消,那么cancel()方法会执行失败,方法返回false。

(3)如果这个任务已开始执行了,那么这个取消方法将不会直接取消该任务,而是会根据我们填的参数mayInterruptIfRunning做判断:

  1. true:取消任务
  2. false:如果任务正在执行,则会继续执行;如果任务还没开始执行,则该任务会被取消,未来也不会执行。

 

用FutureTask来创建Future

  1. 用FutureTask来获取Future和任务的结果
  2. FutureTask是一种包装器,可以把Callable转化成Future和Runnable,它同时实现两者的接口
public class Demo7 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = ()-> {
            System.out.println("任务正在执行");
            Random random = new Random();
            Thread.sleep(2000);
            return random.nextInt(100);
        };

        FutureTask<Integer> integerFutureTask = new FutureTask<>(callable);

        //把FutureTask当作Runnable来用即可
        new Thread(integerFutureTask).start();
        

        //当然,也可以把他放在线程池中
//        ExecutorService executorService = Executors.newCachedThreadPool();
//        executorService.submit(integerFutureTask);


        //获取任务结果
        Integer integer = integerFutureTask.get();
        System.out.println("运行结果integer = " + integer);
    }
}

 

posted @ 2022-05-06 23:54  nicechen  阅读(245)  评论(0编辑  收藏  举报