java线程治理法宝2: Future和Callable(可以处理后续结果,后来的我们)

Future

future的核心思想是:一个方法的计算过程可能非常耗时,一直在原地等待方法返回,显然不明智。可以把该计算过程放到线程池去执行,并通过Future去控制方法的计算过程,在计算出结果后直接获取该结果。

可以通俗的理解为"ajax版本的runnable",屁如:比如去吃早点时,点了包子和凉菜,包子需要等3分钟,凉菜只需1分钟,如果是串行的一个执行,在吃上早点的时候需要等待4分钟,但是因为你在等包子的时候,可以同时准备凉菜,所以在准备凉菜的过程中,可以同时准备包子,这样只需要等待3分钟。那Future这种模式就是后面这种执行模式。

Future常用方法介绍

Future保存异步计算的结果,可以在我们执行任务时去做其他工作,并提供了以下几个方法

* cancel(boolean mayInterruptIfRunning):试图取消执行的任务,参数为true时直接中断正在执行的任务,否则直到当前任务执行完成,成功取消后返回true,否则返回false

* isCancel():判断任务是否在正常执行完前被取消的,如果是则返回true

* isDone():判断任务是否已完成

* get():等待计算结果的返回,如果计算被取消了则抛出

* get(long timeout,TimeUtil unit):设定计算结果的返回时间,如果在规定时间内没有返回计算结果则抛出TimeOutException

Runnable与Callable不同点

1. Runnable不返回任务执行结果,Callable可返回任务执行结果

2. Callable在任务无法计算结果时抛出异常,而Runnable不能

3. Runnable任务可直接由Thread的start方法或ExecutorService的submit方法去执行

 使用Future的好处

1. 获取任务的结果,判断任务是否完成,中断任务

1. Future的get方法很好的替代的了Thread.join或Thread,join(long millis)

2. Future的get方法可以判断程序代码(任务)的执行是否超时

Future图解

 

v get() 返回任务计算结果

package com.zhang.myjuc.a8.future;

import java.util.concurrent.*;

/**
 * FutureDemo:Future的基本使用
 * Callable<T>:返回结果并可能引发异常的任务。实现者定义了一个没有参数的方法call。
 * Callable接口与Runnable类似,因为它们都是为实例可能由另一个线程执行的类设计的。但是,Runnable不返回结果,也不能抛出检查过的异常。
 *
 * @author zhangxiaoxiang
 * @date 2020/08/26
 */
public class FutureDemo {
    public static void main(String[] args) {
        //最新阿里规约,这里为了简介,但是不用线程池工厂(要使用带有ThreadFactory参数的ThreadPoolExecutor构造方法哦,
        // 这样你就可以方便的设置线程名字啦。)
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 
                60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
        Future<String> future = executor.submit(() -> "返回任务执行结果String类型:长草颜团子(lambda写法写法)");
        // Future<String> future = executor.submit(new CallableTask());
        try {
            //返回任务计算结果哈
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }finally {
            executor.shutdown();
        }
    }

    /**
     * 任务常规写法(lambda写法不利于初学时理解,这里添加一个常规写法)
     */
    static class CallableTask implements Callable<String>{
        @Override
        public String call() throws Exception {
            return "返回任务执行结果String类型:长草颜团子(非lambda写法写法)";
        }
    }

}

批量提交任务时,用List来批量接收结果   get(i)的使用

package com.zhang.myjuc.a8.future;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;

/**
 * MultiFutures:批量提交任务时,用List来批量接收结果
 *
 * @author zhangxiaoxiang
 * @date 2020/08/26
 */
public class MultiFutures {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 4,
                60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20));
        ArrayList<Future> futures=new ArrayList<>();
        //20个线程执行注意上面线程池参数(最大线程池数量+队列排队容量>=20才行哈)
        for (int i = 0; i < 20; i++) {
            //JDK 8 lamdba写法
            Future<Integer> future = executor.submit(()->{
                //模拟任务耗时
                Thread.sleep(3000);
                return new Random().nextInt();
            });
            //用List来批量接收结果
            futures.add(future);
        }
        // Thread.sleep(5000);
        for (int i = 0; i < 20; i++) {
            //返回列表中指定位置的元素 get(i)
            Future future = futures.get(i);
            try {
                System.out.println(future.get());
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
    }

}

Future 异常处理(如果任务完成,返回true。完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法将返回true)

package com.zhang.myjuc.a8.future;

import java.util.concurrent.*;

/**
 * FutureException:Future处理异常(如果任务完成,返回true。完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法将返回true)
 * get方法过程中抛出异常,for循环为了演示抛出Exception的时机:并不是说一产生异常就抛出,直到我们get执行时,才会抛出。
 *
 * @author zhangxiaoxiang
 * @date 2020/08/26
 */
public class FutureException {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 20,
                60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20));
        Future<Integer> future = executor.submit(() -> {
            throw new IllegalArgumentException("Callable抛出异常");
        });
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
            try {
                Thread.sleep(500);
                //如果任务完成,返回true。完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法将返回true。
                System.out.println("如果任务完成,返回true。完成可能是由于正常终止、异常或取消——在所有这些情况下," +
                        "此方法将返回true,本次结果是===>"+future.isDone());
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("InterruptedException  异常");
            } catch (ExecutionException e) {
                e.printStackTrace();
                System.out.println("ExecutionException  异常");
            }
        }
    }

}

 执行结果

 

 Future 演示超时 get(2000, TimeUnit.MILLISECONDS)

package com.zhang.myjuc.a8.future;

import java.util.concurrent.*;

/**
 * FutureTimeout:演示get的超时方法,需要注意超时后处理,调用future.cancel()。演示cancel传入true和false的区别,
 * 代表是否中断正在执行的任务。
 *
 * @author zhangxiaoxiang
 * @date 2020/08/26
 */
public class FutureTimeout {
    private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告");
    private static final ExecutorService exec = Executors.newFixedThreadPool(10);
    static class Ad {
        String name;
        public Ad(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Ad{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    static class FetchAdTask implements Callable<Ad> {

        @Override
        public Ad call() throws Exception {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("sleep期间被中断了");
                return new Ad("被中断时候的默认广告");
            }
            return new Ad("旅游订票哪家强?找某程");
        }
    }
    public void printAd() {
        Future<Ad> f = exec.submit(new FetchAdTask());
        Ad ad;
        try {
            //如果有必要,等待计算完成的时间最多为给定的时间,然后检索其结果(如果可用)
            ad = f.get(2000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            ad = new Ad("被中断时候的默认广告");
        } catch (ExecutionException e) {
            ad = new Ad("异常时候的默认广告");
        } catch (TimeoutException e) {
            ad = new Ad("超时时候的默认广告");
            System.out.println("超时,未获取到广告");
            boolean cancel = f.cancel(true);
            System.out.println("cancel的结果:" + cancel);
        }
        exec.shutdown();
        System.out.println(ad);
    }

    public static void main(String[] args) {
        FutureTimeout timeout = new FutureTimeout();
        timeout.printAd();
    }
}

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值