异步线程池

异步&线程池

为了节约时间和提高吞吐量,我们要做一些异步请求

1、初始化线程的4种方式

​ 1,继承Thread

​ 2,实现Runnable接口

​ 3,实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)

​ 4,线程池

方式1和方式2:主线程无法获取线程的运算结果。不适合当前场景

方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致服务器资源耗尽

方式4:通过如下两种方式初始化线程池

Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,unit,workQueue,threadFactory,handler)

通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。

方式一实现代码如下:

1,继承Thread
public class ThreadTest {
    public static void main(String[] args) {
           System.out.println("main....start....");
           Thread01 thread01 = new Thread01();
           thread01.start();//启动线程
           System.out.println("main....end....");
        }
    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程: "+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果: "+i);
        }
    }
}
main....start....
main....end....
当前线程:12
运行结果:5

方式二实现代码如下

2,实现Runnable接口
       public static class Runable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程: "+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果: "+i);
        }
    }

main方法中
        System.out.println("main....start....");
       	Runable01 runable01 = new Runable01();
        new Thread(runable01).start();
        System.out.println("main....end....");
main....start....
main....end....
当前线程:12
运行结果:5

第三种方式

public static class Callable01 implements Callable{
        @Override
        public Object call() throws Exception {
            System.out.println("当前线程: "+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果: "+i);
            return i;
        }
    }

main方法中
    FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
    new Thread(futureTask).start();
System.out.println("main....end....");

可以看到Callable接口中直接结束了

异步线程池_第1张图片

所以我们将采取FutureTask的方式来启动Callable的线程,根据FutureTask源码

异步线程池_第2张图片

继而new出来返回FutureTask,FutureTask又继承RunnableFuture,而RunnableFuture又分别继承Runnable,Future

异步线程池_第3张图片

所以它的启动方式就是FutureTask futureTask = new FutureTask<>(new Callable01());new Thread(futureTask).start();

运行结果如下

main....start....
main....end....
当前线程:12
运行结果:5

Callable最大的好处是FutureTask 我们假设后台运行的很慢,我们还希望后台返回这个Callable的计算结果,就可以使用FutureTask ,它有一个方法.get

等异步方法执行完,返回它的结果

Integer integer = futureTask.get();
//等待整个线程执行完成,获取返回结果


修改main方法
    Integer integer = futureTask.get();
System.out.println("main....end...."+integer);

	main....start....
当前线程:12
运行结果:5
main....end....+5

所以Integer integer = futureTask.get();是一个阻塞等待

futureTask不仅可以接受Callable,还接受Runnable,如果是Runnable,还可以传一个对象,让这个对象接受参数

异步线程池_第4张图片

第四种方式

给线程池直接提交任务。

为什么使用线程池?如果我们后来的项目中异步比较多,每次都进行原生代码new Thread().start(),没执行一个线程就开启一个start(存在问题)

我们以后在业务代码里,以上三种启动线程的方式都不能用 避免大量new Thread造成资源消耗完,应该将所有的多线程异步任务交给线程池执行

JUC中最快得到线程池

ExecutorService executorService = Executors.newFixedThreadPool(10);
//10代表有十个空闲线程   当前系统中池只有一两个,每个异步任务,提交给线程让他自己去执行就行

并不应该是每运行一次就创建一个线程池,应该是一个线程池,大家将所有任务都交给这个线程池来处理

要想访问线程池

public static ExecutorService executorService = Executors.newFixedThreadPool(10);

异步线程池_第5张图片

里面有submit,可以将一个Runnable或Callable的任务,或者使用execute让它执行

submit跟execute两个区别

如果是submit给线程池中添加一个任务,我们可以获取任务的返回值;如果是execute,直接让线程池执行我们这个操作,返回类型是void 都是给线程池提交异步请求

main中执行
 executorService.execute(new Runable01());
main....start....
main....end....
当前线程:12
运行结果:5

这是我们将任务提交给线程池,而不是我们自己在new

 给线程池直接提交任务。
         * executorService.execute(new Runable01());
         * 1,创建
         *   1)Executors
         *   2)new ThreadPoolExecutor();
         *   Future:可以获得到异步结果
         *
         * 区别
         * 1,2不能获取返回值3可以获取返回值
         * 1,2,3都不能控制资源
         * 4,可以控制资源,性能稳定
         *
         */

2,线程池的七大参数

/**
         * int corePoolSize【5】, 我们的线程数量总是在池中保持着  就算系统当前是空闲的,也是在池总一直有的,等待接收新任务的 除非设置allowCoreThreadTimeOut(允许核心线程超时,这样核心线程空闲就被回收了,否则就不回收)
         * 核心线程数[一直存在除非设置allowCoreThreadTimeOut]  线程池  创建好以后准备就绪的线程数量,就等待来接受异步任务去执行  5个 Thread thread = new Thread()  thread.start()
         int maximumPoolSize, 相当于线程池最大数量;控制资源并发
         long keepAliveTime,存活时间  如果当前我们线程数量大于核心线程数的时候  释放空闲线程(maximumPoolSize-corePoolSize)  只要线程空闲大于指定keepAliveTime
         TimeUnit unit, 时间单位
         BlockingQueue<Runnable> workQueue,阻塞队列  如果任务有很多,就会将目前多的任务放在队列里面   只要有线程空闲,就会去队列里面取出新的任务继续执行
         ThreadFactory threadFactory, 线程的创建工厂
         RejectedExecutionHandler handler  如果队列满了,按照我们指定的拒绝策略拒绝执行任务(默认使用丢弃策略AbortPolicy)

         工作顺序:
         1)线程池创建好,准备好core数量的核心线程,准备接受任务
         1.1core满了,就将再进来的任务放到阻塞队列中,空闲的core就会自己去阻塞队列获取任务执行
         1.2阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
         1.3max满了就用拒绝策略RejectedExecutionHandler拒绝任务
         1.4max都执行完成,有很多空闲  在指定的时间【keepAliveTime】以后,释放max-core这些线程

         new LinkedBlockingDeque<>():默认是Integer的最大值。内存不够

         */
  ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );

默认ThreadFactory

异步线程池_第6张图片

拒绝策略(默认使用丢弃策略AbortPolicy)

异步线程池_第7张图片

一个简单面试题:

一个线程池core7 max20 queue 50 100并发进来怎么分配
首先 7个会立即得到执行 50个进入队列 再开13个进行执行 剩下30个采用拒绝策略
如果不想抛弃还要执行 CallerRunsPolicy;同步方法   也可以尝试使用抛弃以前老数据

3,Executors中常见四种线程池

  • newCachedThreadPool() core是0,所有都可以回收

    异步线程池_第8张图片

    创建一个可缓存线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程

  • newFixedThreadPool() 固定大小 core=max 都不可被回收

    异步线程池_第9张图片

    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

  • newScheduledThreadPool() 定时任务线程池

    异步线程池_第10张图片

    创建一个定长线程池,支持定时及周期性任务执行

  • newSingleThreadExecutor() 单线程的线程池,后台从队列里面获取任务 挨个执行

    异步线程池_第11张图片

    4,开发中为什么使用线程池

    • 降低资源的消耗

      • 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
    • 提高响应速度

      • 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
    • 提高线程的可管理性

      • 线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁不仅会消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配。

CompletableFuture异步编排

业务场景:

查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多时间

异步线程池_第12张图片

假如商品详细页的每个查询,需要如下标注的时间才能完成

那么,用户需要5.5s才能看到商品详细页的内容。很显然是不能接受的

如果多个线程同时完成这6步,也许就只需要1.5s就完成响应

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

虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不 方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的 初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果,为 什么不能用观察者设计模式当计算结果完成及时通知监听者呢? 很多语言,比如 Node.js,采用回调的方式实现异步编程。Java 的一些框架,比如 Netty,自 己扩展了 Java 的 Future接口,提供了addListener等多个扩展方法;Google guava 也提供了 通用的扩展 Future;Scala 也提供了简单易用且功能强大的 Future/Promise 异步编程模式。 作为正统的 Java 类库,是不是应该做点什么,加强一下自身库的功能呢? 在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以 通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。 CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过get方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用

CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。

异步线程池_第13张图片

CompletableFuture是jdk1.8以后添加的功能 CompletableFuture就类似于vue中promise的ajax请求,执行完了就.then

CompletableFuture提供了四个静态方法来创建一个异步操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Im8GqjtU-1651988685326)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220507233226681.png)]

1创建异步对象

 public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        System.out.println("main....start....");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
        }, executor);
        System.out.println("main....end....");
        executor是定义好的线程池,如果没有定义就用默认的
             public static ExecutorService executor = Executors.newFixedThreadPool(10);
        无返回值
main....start....
main....end....
当前线程: 12
运行结果: 5
  CompletableFuture.supplyAsync(()->{
            System.out.println("当前线程: "+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果: "+i);
            return i;
        },executor);
   executor是定义好的线程池,如果没有定义就用默认的
             public static ExecutorService executor = Executors.newFixedThreadPool(10);
有返回值
main....start....
main....end....
当前线程: 12
运行结果: 5
 System.out.println("main....start....");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor);
        Integer integer = future.get();
        System.out.println("main....end...."+integer);
    }
   executor是定义好的线程池,如果没有定义就用默认的
             public static ExecutorService executor = Executors.newFixedThreadPool(10);
有返回值
main....start....
当前线程: 12
运行结果: 5
main....end....5

2计算完成时回调方法

异步线程池_第14张图片

whenCompletable可以处理正常和异常的计算结果,exceptionally处理异常情况

whenCompletable和whenCompletableAsync的区别:

  • whenCompletable:是执行当前任务的线程执行继续执行whenCompletable的任务
  • whenCompletableAsync:是执行把whenCompletableAsync这个任务继续提交给线程池来进行执行

方法不以Asyc结尾,意味着Action使用相同的线程执行,而Asyc可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

whenComplete没有异常

 System.out.println("main....start....");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).whenComplete((res,excption)->{
            System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
        });
//        Integer integer = future.get();
        System.out.println("main....end....");
main....start....
当前线程: 12
运行结果: 5
异步任务成功完成了。。。结果是:5;异常是:null
main....end....

whenComplete有异常

System.out.println("main....start....");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).whenComplete((res,excption)->{
            System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
        });
//        Integer integer = future.get();
        System.out.println("main....end....");
main....start....
当前线程: 12
main....end....
异步任务成功完成了。。。结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero

出现异常后还能进行处理exceptionally 异常处理逻辑

  System.out.println("main....start....");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).whenComplete((res,excption)->{
            //虽然能得到异常信息,但是没法修改返回数据
            System.out.println("异步任务成功完成了。。。结果是:"+res+";异常是:"+excption);
        }).exceptionally(throwable -> {
            //可以感知异常,同时返回默认值
            return 10;
        });
                //R apply(T,t);
        Integer integer = future.get();
        System.out.println("main....end...."+integer);
    }
main....start....
当前线程: 12
异步任务成功完成了。。。结果是:null;异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
main....end....10

3handle方法

异步线程池_第15张图片

和complete一样,可对结果做最后的处理(可处理异常),可改变返回值

有异常时
     //方法执行完成后的处理,无论是成功完成还是失败完成
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).handle((res,thr)->{
            if (res!=null){
                return res*2;
            }
            if (thr!=null){
                return 0;
            }
            return 0;
        });
//        R apply(T t, U u);
        Integer integer = future.get();
        System.out.println("main....end...."+integer);
    }
main....start....
当前线程: 12
main....end....0
因为有异常,handle就将返回值修改为0
无异常时
     //方法执行完成后的处理,无论是成功完成还是失败完成
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2
            System.out.println("运行结果: " + i);
            return i;
        }, executor).handle((res,thr)->{
            if (res!=null){
                return res*2;
            }
            if (thr!=null){
                return 0;
            }
            return 0;
        });
//        R apply(T t, U u);
        Integer integer = future.get();
        System.out.println("main....end...."+integer);
    }
main....start....
当前线程: 12
运行结果: 5
main....end....10

异步返回结果为5,在handle中被修改了

4线程串行化方法

异步线程池_第16张图片

thenApply方法:当一个线程依赖另一个线程时,获取上一个任务的返回的结果,并返回当前任务的返回值

异步线程池_第17张图片

异步线程池_第18张图片

 /**
         * 线程串行化
         * 1)thenRun:不能获取到上一步的执行结果,无返回值
         * .thenRunAsync(() -> {
         *             System.out.println("任务二启动了。。。。");
         *         }, executor);
         *2)thenAcceptAsync:能接收上一步结果,但是无返回值
         *.thenAcceptAsync(res->{
         *              System.out.println("任务二启动了"+res);
         *          },executor);
         *3)thenApplyAsync:能接收上一步结果,有返回值
         */   
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).thenApplyAsync(res -> {
            System.out.println("任务二启动了" + res);
            return "Hello" + res;
        }, executor);
        //future.get()是一个阻塞方法
        System.out.println("main....end...."+future.get());
    }
main....start....
当前线程: 12
运行结果: 5
任务二启动了5
main....end....Hello5

thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果

image-20220508102236075

异步线程池_第19张图片

 /**
         * 线程串行化
         * 1)thenRun:不能获取到上一步的执行结果,无返回值
         * .thenRunAsync(() -> {
         *             System.out.println("任务二启动了。。。。");
         *         }, executor);
         *2)thenAcceptAsync:能接收上一步结果,但是无返回值
         *.thenAcceptAsync(res->{
             System.out.println("任务二启动了"+res);
         },executor);
         */
         CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).thenAcceptAsync(res->{
             System.out.println("任务二启动了"+res);
         },executor);
        System.out.println("main....end....");
    }
main....start....
当前线程: 12
运行结果: 5
main....end....
任务二启动了5

thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行thenRun的后续操作


        /**
         * 线程串行化
         * 1)thenRun:不能获取到上一步的执行结果
         * .thenRunAsync(() -> {
            System.out.println("任务二启动了。。。。");
        }, executor);
         */
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).thenRunAsync(() -> {
            System.out.println("任务二启动了。。。。");
        }, executor);
        System.out.println("main....end....");
    }
main....start....
当前线程: 12
运行结果: 5
main....end....
任务二启动了。。。。

带有Async默认是异步执行的,同之前。

以上都要前置任务成功完成

5两任务组合-都要完成

异步线程池_第20张图片

异步线程池_第21张图片

两个任务必须都完成,触发该任务

thenCombine:组合两个future,获取两个future的返回结果,并返回当前任务的返回值

异步线程池_第22张图片

异步线程池_第23张图片

 /**
         * 两个都完成
         */
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            System.out.println("任务二结束: ");
            return "hello";
        }, executor);
//        R apply(T t, U u);
        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
            return f1 + ":" + f2 + "->giao";
        }, executor);
        System.out.println("main....end...."+future.get());
    }


main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
任务二结束: 
main....end....5:hello->giao

thenAcceptBoth:组合两个future,获取两个future的返回结果,然后处理任务,没有返回值

异步线程池_第24张图片

 /**
         * 两个都完成
         */
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            System.out.println("任务二结束: ");
            return "hello";
        }, executor);
//        void accept(T t, U u);
        future01.thenAcceptBothAsync(future02,(f1,f2)->{
            System.out.println("任务3开始。。。之前的结果:"+f1+".....>"+f2);
        },executor);
        System.out.println("main....end....");
    }
main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
任务二结束: 
main....end....
任务3开始。。。之前的结果:5.....>hello

runAfterBoth:组合两个future,不需要获取future的结果,只需要两个future处理完任务后,处理该任务

异步线程池_第25张图片

  /**
         * 两个都完成
         */
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            System.out.println("任务二结束: ");
            return "hello";
        }, executor);

        future01.runAfterBothAsync(future02,()->{
            System.out.println("任务三开始");
        },executor);
        System.out.println("main....end....");
    }
main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
任务二结束: 
main....end....
任务三开始

6两个任务组合-一个完成

异步线程池_第26张图片

当两个任务中,任意一个 future 任务完成的时候,执行任务。

applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。

   /**
         * 两个任务,只要有一个完成,我们就执行任务3
         * runAfterEitherAsync:不感知结果,自己没有返回值
         * acceptEitherAsync:感知结果,自己没有返回值
         * applyToEitherAsync:自己感知结果,有返回值
         */      
CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
            System.out.println("任务3开始。。。之前的结果" + res);
            return res.toString() + "->giao";
        }, executor);

        System.out.println("main....end...."+future.get());
    }
main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
任务3开始。。。之前的结果5
main....end....5->giao
任务二结束: 

acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
异步线程池_第27张图片

 CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务二结束: ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }, executor);


        /**
         * 两个任务,只要有一个完成,我们就执行任务3
         * runAfterEitherAsync:不感知结果,自己没有返回值
         * acceptEitherAsync:感知结果,自己没有返回值
         */
       /* future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务3开始。。。之前的结果");
        },executor);*/

        future01.acceptEitherAsync(future02,(res)->{
            System.out.println("任务3开始。。。之前的结果"+res);
        },executor);
        System.out.println("main....end....");
    }

main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
main....end....
任务3开始。。。之前的结果
任务二结束: 

runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值

 /**
         * 两个任务,只要有一个完成,我们就执行任务3
         */
        future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务3开始。。。之前的结果");
        },executor);
        System.out.println("main....end....");
    }

 CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            System.out.println("任务二结束: ");
            return "hello";
        }, executor);

main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
任务二结束: 
main....end....
任务3开始。。。之前的结果

这个操作两个线程都完成了,无法查看runAfterEither的效果所以对代码future02作出修改

CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一线程启动了: " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("任务一结束: ");
            return i;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务二线程启动了: " + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务二结束: ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello";
        }, executor);


  /**
         * 两个任务,只要有一个完成,我们就执行任务3
         * runAfterEitherAsync:不感知结果,自己业务返回值
         */
        future01.runAfterEitherAsync(future02,()->{
            System.out.println("任务3开始。。。之前的结果");
        },executor);
        System.out.println("main....end....");
    }
main....start....
任务一线程启动了: 12
任务一结束: 
任务二线程启动了: 13
main....end....
任务3开始。。。之前的结果
任务二结束: 

7多任务组合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8fqmY4S8-1651988685333)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220508113138087.png)]

allOf:等待所有任务完成

CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            return "hello.jpg";
        });

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品de属性");
            return "黑色+256G";
        });

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品介绍");
            return "华为";
        });

//        futureImg.get();
//        futureAttr.get();
//        futureDesc.get();
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        allOf.get();//等待所有结果完成
//        allOf.join();

main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....

当一个线程执行比较慢时

  CompletableFuture futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            return "hello.jpg";
        });

        CompletableFuture futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品de属性");
            return "黑色+256G";
        });

        CompletableFuture futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品介绍");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "华为";
        });

//        futureImg.get();
//        futureAttr.get();
//        futureDesc.get();
        CompletableFuture allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//        allOf.get();//等待所有结果完成
//        allOf.join();

        System.out.println("main....end....");
    }

输出结果居然没有查询商品介绍 所有任务都没执行完就结束了

main....start....
查询商品图片信息
查询商品de属性
main....end....

改为线程池 无线存活阻塞

CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            return "hello.jpg";
        },executor);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品de属性");
            return "黑色+256G";
        },executor);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品介绍");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "华为";
        },executor);

//        futureImg.get();
//        futureAttr.get();
//        futureDesc.get();
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//        allOf.get();//等待所有结果完成
//        allOf.join();

        System.out.println("main....end....");
    }


main....start....
查询商品图片信息
查询商品de属性
main....end....
查询商品介绍

所以还不如直接

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
     allOf.get();//等待所有结果完成

想要获取到future中的内容

System.out.println("main....end...."+futureImg.get()+"=>"+futureAttr.get()+"=>"+futureDesc.get());
main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....hello.jpg=>黑色+256G=>华为

anyOf:只要有一个任务完成

    CompletableFuture anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();
 
  
main....start....
查询商品图片信息
查询商品de属性
main....end....hello.jpg
查询商品介绍
 } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "华为";
    },executor);

// futureImg.get();
// futureAttr.get();
// futureDesc.get();
CompletableFuture allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
// allOf.get();//等待所有结果完成
// allOf.join();

    System.out.println("main....end....");
}



```console
main....start....
查询商品图片信息
查询商品de属性
main....end....
查询商品介绍

所以还不如直接

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
     allOf.get();//等待所有结果完成

想要获取到future中的内容

System.out.println("main....end...."+futureImg.get()+"=>"+futureAttr.get()+"=>"+futureDesc.get());
main....start....
查询商品图片信息
查询商品de属性
查询商品介绍
main....end....hello.jpg=>黑色+256G=>华为

anyOf:只要有一个任务完成

    CompletableFuture anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();
 
  
main....start....
查询商品图片信息
查询商品de属性
main....end....hello.jpg
查询商品介绍

你可能感兴趣的:(Java,java,开发语言)