JAVA多线程(二十四)Java多线程之CompletableFuture类

1.JAVA多线程(二十四)Java多线程之CompletableFuture类

1.1 什么是Future

  Future是Java 5添加的类,用来描述一个异步计算的结果。你可以使用isDone方法检查计算是否完成,或者使用get阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel方法停止任务的执行。

package com.yuanxw.chapter24;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class FutureExample {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        // 构造一个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 提交线程任务
        Future<Integer> future = executorService.submit(() -> {
   
            try {
   
                System.out.println(String.format("当前【%s】线程工作-开始...", Thread.currentThread().getName()));
                TimeUnit.SECONDS.sleep(10);
                System.out.println(String.format("当前【%s】线程工作-结束...", Thread.currentThread().getName()));
                return ThreadLocalRandom.current().nextInt(100);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
                return -1;
            }
        });
        System.out.println(String.format("【%s】在等待线程执行结果...", Thread.currentThread().getName()));
        System.out.println("是否执行结束:"+future.isDone());
        System.out.println(future.get());
        System.out.println("是否执行结束:"+future.isDone());
    }
}

执行结果:

当前【pool-1-thread-1】线程工作-开始...
【main】在等待线程执行结果...
是否执行结束:false
当前【pool-1-thread-1】线程工作-结束...
76
是否执行结束:true

1.2 Future的局限性

  虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时地得到计算结果。CompletableFuture的出现解决了Future模式的缺点。

  • 不能手动完成:
    • 当你写了一个函数,用于通过一个远程API获取一个电子商务产品最新价格。因为这个 API 太耗时,你把它允许在一个独立的线程中,并且从你的函数中返回一个 Future。现在假设这个API服务宕机了,这时你想通过该产品的最新缓存价格手工完成这个Future 。你会发现无法这样做。
  • Future的结果在非阻塞的情况下,不能执行更进一步的操作:
    • Future 不会通知你它已经完成了,它提供了一个阻塞的 get() 方法通知你结果。你无法给 Future 植入一个回调函数,当 Future 结果可用的时候,用该回调函数自动的调用 Future 的结果。
  • 多个Future不能串联在一起组成链式调用:
    • 有时候你需要执行一个长时间运行的计算任务,并且当计算任务完成的时候,你需要把它的计算结果发送给另外一个长时间运行的计算任务等等。你会发现你无法使用 Future 创建这样的一个工作流。
      不能组合多个 Future 的结果
      假设你有10个不同的Future,你想并行的运行,然后在它们运行未完成后运行一些函数。你会发现你也无法使用 Future 这样做。
  • 没有异常处理:
    • Future API 没有任务的异常处理结构居然有如此多的限制,幸好我们有CompletableFuture,你可以使用 CompletableFuture 达到以上所有目的。

1.3 什么是CompletableFuture

   在Java中CompletableFuture用于异步编程,异步编程是编写非阻塞的代码,运行的任务在一个单独的线程,与主线程隔离,并且会通知主线程它的进度,成功或者失败。在这种方式中,主线程不会被阻塞,不需要一直等到子线程完成。主线程可以并行的执行其他任务。使用这种并行方式,可以极大的提高程序的性能。
   CompletableFuture 实现了 Future 和 CompletionStage接口,并且提供了许多关于创建,链式调用和组合多个 Future 的便利方法集,而且有广泛的异常处理支持。
   CompletableFuture和Java8的Stream搭配使用,使用对于一些并行访问的耗时操作有很大的操作。

CompletableFuture继承结构关系图

在这里插入图片描述
CompletableFuture类实现了CompletionStage和Future接口,所以你还是可以像以前一样通过阻塞或者轮询的方式获得结果,尽管这种方式不推荐使用。

1.4 CompletableFuture方法分类

1.4.1. 创建CompletableFuture对象

  以Async结尾并且没有指定Executor的方法会使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。runAsync方法也好理解,它以Runnable函数式接口类型为参数,所以CompletableFuture的计算结果为空。supplyAsync方法以Supplier<U>函数式接口类型为参数,CompletableFuture的计算结果类型为U。
CompletableFuture的静态工厂方法:

方法名 描述
runAsync(Runnable runnable) 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。
runAsync(Runnable runnable, Executor executor) 使用指定的thread pool执行异步代码。
supplyAsync(Supplier supplier) 使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值。
supplyAsync(Supplier supplier, Executor executor) 使用指定的thread pool执行异步代码,异步操作有返回值。
  • CompletableFuture.completedFuture是一个静态辅助方法,用来返回一个已经计算好的CompletableFuture。
    /**
     * Returns a new CompletableFuture that is already completed with
     * the given value.
     *
     * @param value the value
     * @param <U> the type of the value
     * @return the completed CompletableFuture
     */
    public static <U> CompletableFuture<U> completedFuture(U value) {
   
        return new CompletableFuture<U>((value == null) ? NIL : value);
    }
  • 而以下四个静态方法用来为一段异步执行的代码创建CompletableFuture对象:
    /**
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the {@link ForkJoinPool#commonPool()} with
     * the value obtained by calling the given Supplier.
     *
     * @param supplier a function returning the value to be used
     * to complete the returned CompletableFuture
     * @param <U> the function's return type
     * @return the new CompletableFuture
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
   
        return asyncSupplyStage(asyncPool, supplier);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the given executor with the value obtained
     * by calling the given Supplier.
     *
     * @param supplier a function returning the value to be used
     * to complete the returned CompletableFuture
     * @param executor the executor to use for asynchronous execution
     * @param <U> the function's return type
     * @return the new CompletableFuture
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {
   
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the {@link ForkJoinPool#commonPool()} after
     * it runs the given action.
     *
     * @param runnable the action to run before completing the
     * returned CompletableFuture
     * @return the new CompletableFuture
     */
    public static CompletableFuture<Void> runAsync(Runnable runnable) {
   
        return asyncRunStage(asyncPool, runnable);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the given executor after it runs the given
     * action.
     *
     * @param runnable the action to run before completing the
     * returned CompletableFuture
     * @param executor the executor to use for asynchronous execution
     * @return the new CompletableFuture
     */
    public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {
   
        return asyncRunStage(screenExecutor(executor), runnable);
    }
1.4.2. 主动完成计算
方法名 描述
get() 方法同步等待结果。
get(timeout,unit) get(timeout,unit)签名方法,给定时间,然后返回其结果,如果超时,抛出异常
join() 完成后返回结果值,如果完成异常,则返回(未检查)异常。
getNow() 如果已完成,则返回结果值(或抛出任何遇到的异常),否则返回给定的值IfAbsent。
package com.yuanxw.chapter24;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CompletableFutureExample1 {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        runAsync();
        // get() 方法同步等待结果。
        get();

        // get(timeout,unit)签名方法,给定时间,然后返回其结果,如果超时,抛出异常
        get(3,TimeUnit.SECONDS);

        // join() 完成后返回结果值,如果完成异常,则返回(未检查)异常。
        join();

        // getNow() 如果已完成,则返回结果值(或抛出任何遇到的异常),否则返回给定的值IfAbsent。
        getNow();
    }

    /**
     * runAsync()异步执行runAsync返回的CompletableFuture是没有返回值的。
     * supplyAsync()异步执行runAsync返回的CompletableFuture是有返回值的。
     执行结果:
     =====【main】执行runAsync()签名方法-开始=====
     Hello world!!!
     =====【main】执行runAsync()签名方法-结束=====
     * @throws ExecutionException
     * @throws InterruptedException
     */
    private static void runAsync() throws ExecutionException, InterruptedException {
   
        System.out.println(String.format("=====【%s】执行runAsync()签名方法-开始=====", Thread.currentThread().getName()));
        CompletableFuture.runAsync(
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值