Future,FutureTask,CompletableFuture

最近项目里有使用到FutureTask这一组件,顺便写个简要总结。

1. 定义:
Future,FutureTask和CompletableFuture都代表了异步计算的结果。

2. Future和FutureTask和CompletableFuture的关系
Future,FutureTask,CompletableFuture_第1张图片
如图所示,Future和FutureTask都能异步的获取线程执行结果,但是FutureTask不仅实现Future接口,并且实现了Runable接口,所以我们可以直接将FutureTask提交到线程池执行,同时也可以获取执行结果,但是Future仅支持获取Callable的执行结果,所以可见FutureTask功能更加全面且方便。
FutureTask底层是基于AQS实现的,具体原理可以看源码。

Future,FutureTask,CompletableFuture_第2张图片
CompletableFuture是jdk1.8以后出现的,和前面的Future以及FutureTask有很大区别,功能更加强大且复杂,而且融入了大量的流式编程思想,详细介绍可以看这篇博客。

3. 应用场景
Java中线程的实现方式一般有实现Runable接口,实现Callable接口,继承Thread类三种。而Runable和Thread的run方法都是void,也就是没有返回值,所以这种情况下获取线程的返回值就要使用线程间通信的手段,一般比较麻烦;或者使用Callable接口,但是Callable接口本身只能支持同步的结果获取,所以Future和FutureTask就应时而生了。
Future和FutureTask提供一种轻量级的获取异步任务结果的手段。
而CompletableFuture则是提供了更加丰富的api,来进行异步的计算,转化,消费,多个CompletableFuture合并,返回结果等,相对来说比较重量级。

4. Demo:
简单实现了两个Demo,模拟任务提交,分别实现了基于Future和FutureTask的结果获取,以及同步和异步两种方式,仔细理解体会,下次就能想到使用这一基础并发组件。

FutureCallableDemo

public class Job implements Callable {

    @Override
    public Integer call() throws Exception {
        Thread.sleep(1000);
        System.out.println("这是子线程");
        return 1;
    }
}

public class FutureCallableDemo {

    public static void main(String[] args) throws Exception {
        ExecutorService es = Executors.newSingleThreadExecutor();
        Callable callable = new Job();

        /**
         * 同步方式
         */
        //System.out.println(callable.call());

        /**
         * 异步方式
         */
        Future future = es.submit(callable);
        System.out.println("主线程可以做自己的事情");
        System.out.println(future.get());
        es.shutdown();
    }
}

FutureTaskDemo

public class Job implements Callable {

    @Override
    public Integer call() throws Exception {
        Thread.sleep(1000);
        System.out.println("这是子线程");
        return 1;
    }
}

public class FutureTaskDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newSingleThreadExecutor();
        FutureTask futureTask = new FutureTask<>(new Job());

        /**
         * 同步方式
         */
        //futureTask.run();

        /**
         * 异步方式
         */
        es.submit(futureTask);
        System.out.println("主线程可以做自己的事情");
        System.out.println(futureTask.get());
        es.shutdown();
    }
}

CompletableFutureDemo

public class CompletableFutureDemo {

    private static ExecutorService es = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        /**
         * 最基本的Future功能演示
         */
        System.out.println(CompletableFuture.supplyAsync(() -> "mysql IO", es)
                .get());
        System.out.println("--------------------------------------------------------------------------");

        /**
         * combine演示
         */
        CompletableFuture.supplyAsync( () -> 123, es)
                .thenCombine(CompletableFuture.supplyAsync( () -> 456, es), (x, y) -> x + " " + y)
                .whenComplete((s, v) -> System.out.println("合并结果: " + s));
        System.out.println("--------------------------------------------------------------------------");

        /**
         * 创建CompletableFuture对象计算,转化结果,计算完成后进行消费,并返回结果(或者进行纯消费)演示
         */
        List taskList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        CompletableFuture[] cfs = taskList.stream() // stream
                .map(o -> CompletableFuture.supplyAsync(() -> cal(o), es) // 创建CompletableFuture对象
                        .thenApply(h -> Integer.toString(h)) // 结果转化
                        .whenComplete((v, e) -> System.out.println("任务" + v + "完成!result=" + v + ",异常 e=" + e + "," + new Date())) // 计算完成时消费
                )
                .toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(cfs).join(); // 等待所有的CompletableFuture执行完成,然后返回结果
    }
    private static Integer cal(Integer i) {
        try {
            if (i == 1) {
                Thread.sleep(3000);//任务1耗时3秒
            } else if (i == 5) {
                Thread.sleep(5000);//任务5耗时5秒
            } else {
                Thread.sleep(1000);//其它任务耗时1秒
            }
            System.out.println("task线程:" + Thread.currentThread().getName() + "任务i=" + i + ",完成!+" + new Date());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }
}

Github:项目地址
参考文献:
《Java编程思想》
《Java并发编程的艺术》

你可能感兴趣的:(Java并发)