线程池 & 异步编排


1、异步


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


异步1


创建线程的4种方式

  • 1、继承Thread

  • 2、实现Runnable接口

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

  • 4、线程池

    给线程池直接提交任务:

    • service.execute(new Runnable01());

    提交任务的两种方式:

    • 1)、submit 可以获取任务的返回值
    • 2)、executors不获取任务的返回值(只是执行)

总结

我们以后再业务代码里面,以上三种启动线程的方式都不用。将所有的多线程异步任务都交给线程池执行


区别

继承Thread实现Runnable不能得到返回值。实现Callable可以获取返回值
继承Thread实现Runnable实现Callable都不能控制资源,可能导致服务器资源耗尽
线程池可以控制资源,性能稳定。


  • 测试代码
//  测试线程池
public class ThreadTest {

//4、线程池
    //创建一个固定数量的线程池 此处为创建10个
    /* 系统中池只有一两个,每个异步任务,提交给线程池让它去执行 */ //此处为只有一个池
    public static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main ... start ...");

//1、继承Thread
//        Thread01 thread1 = new Thread01();
//        thread1.start(); //启动线程
        /***
         * main ... start ...
         * main ... end ...
         * 当前线程:11
         * 运行结果:5
         */

//2、实现Runnable
//        Runable01 runable01 = new Runable01();
//        new Thread(runable01).start();
        /***
         * main ... start ...
         * main ... end ...
         * 当前线程:11
         * 运行结果:5
         */

//3、实现Callable接口+FutureTask
//        FutureTask<Integer> task = new FutureTask<>(new Callable01());
//        new Thread(task).start();
        /***
         * main ... start ...
         * main ... end ...
         * 当前线程:11
         * 运行结果:5
         */
//3.1)、等待整个线程执行完成,获取返回结果 -> 阻塞等待
//        Integer integer = task.get();
//        System.out.println("返回结果:" + integer);
        /***
         * 可以看到两个执行顺序不一样,使用get()方法需等待task线程执行结束,才可以执行main线程
         * main ... start ...
         * 当前线程:11
         * 运行结果:5
         * 返回结果:5
         * main ... end ...
         */

//4、创建好线程池之后,使用线程池【线程池方式】
//4.1)、给线程池提交任务
//        service.submit(); //可以获取任务的返回值
        service.execute(new Runable01()); //不获取任务的返回值(只是执行)
        /***
         * main ... start ...
         * main ... end ...
         * 当前线程:11
         * 运行结果:5
         */

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

    //1、继承Thread
    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:" + i);
        }
    }

    //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);
        }
    }

    //3、实现Callable接口+FutureTask
    //需要指定泛型。泛型就是方法的返回值类型。
    public static class Callable01 implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:" + i);
            return i;
        }
    }

}

02、线程池


创建线程池方式2:【须传入线程池的7大参数】

ThreadPoolExecutor executor = new ThreadPoolExecutor();


线程池的7大参数

参数说明作用及解释
corePoolSize核心线程数线程池,创建好以后就准备就绪的线程数量,就等待接收异步任务去执行 【只要线程池不销毁,就会一直存在,除非设置了 allowCoreThreadTimeOut (允许核心线程池超时)】 示例:5个 Thread thread = new Thread(); thread.start();
maximumPoolSize最大线程数量控制资源
keepAliveTime存活时间如果当前正在运行的线程数量大于core数量 释放空闲的线程(maximumPoolSize-corePoolSize)。只要线程空闲大于指定的keepAliveTime;
unit时间单位
BlockingQueue workQueue阻塞队列如果任务有很多。就会将多的任务放在队列里面 只要有线程空闲,就会去队列里面取出新的任务继续执行 示例:new LinkedBlockingQueue<>(),默认是Integer的最大值。可能导致内存不够,需要传入压力测试后的定制数量
ThreadFactory线程创建的工厂
RejectedExecutionHandler handler处理队列满了的情况如果队列满了,按照我们指定的拒绝策略,拒绝执行

执行流程

ThreadPoolExecutor executor = new ThreadPoolExecutor(
			5,
            200,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100000),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()
);

说明:

  1. 线程池创建,准备好core数量的核心线程,准备接受任务
  2. core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
  3. 阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量
  4. max都执行完成,(max-core)数量空闲的线程会在keepAliveTime指定的时间后,自动销毁,释放空闲的线程。最终保持到core的大小
  5. 如果线程开到了max数量,还有新任务进来,就会使用RejectedExecutionHandler拒绝任务

示例:

一个线程池 core 7, max 20, queue 50, 100并发进来怎么分配的?

  • 7个会立即执行。
  • 50个进入队列。
  • 队列满了可以再开启线程,再开13【max-core】个进行执行。
  • 剩下30个就是用拒绝策略,拒绝策略一般都是丢弃,如果不想丢弃还要执行,可以使用CallerRunsPolicy策略

常见的4种线程池

线程池说明
newCachedThreadPool创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 core是0,所有都可以回收
newFixedThreadPool创建一个固定大小线程池,可控制线程最大并发数,超出的线程会在队列中等待。core=max,都不可回收
newScheduledThreadPool定时任务的线程池
newSingleThreadExecutor创建一个单线程化的线程池,后台从队列里面获取任务,挨个执行

异步2


2、CompletableFuture异步编排


在这里插入图片描述


01、创建异步对象


CompletableFuture提供了4个静态方法来创建异步对象

public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
  • runAsync()无返回值。
  • supplyAsync()有返回值。

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。

可以传入自定义的线程池。不指定线程池的话会使用默认的线程池

  • 示例
public class ThreadTest {

    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main ... start ...");
//1、runAsync()方法
//        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程:" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果:" + i);
//        }, execute);
        /***
         * main ... start ...
         * main ... end ...
         * 当前线程:11
         * 运行结果:5
         */

//2、supplyAsync方法
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, execute);
        System.out.println("返回值 = " + future.get());
        /***
         * main ... start ...
         * 当前线程:11
         * 运行结果:5
         * 返回值 = 5
         * main ... end ...
         */

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

02、计算结果完成时的回调方法


当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:

//可以处理异常,无返回值,当前一个线程成功执行之后,还可以做别的事情,但是这个线程还是和前一个线程一样
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
//可以处理异常,无返回值,当前一个线程成功执行之后,还可以做别的事情,还是以异步的方式交给线程池进行处理
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
//可以处理异常,有返回值
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)

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

  • 示例
public class ThreadTest {

    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
  	
  	/***
  	*	方法执行完成后的感知
  	*/
 	public static void main(String[] args) throws ExecutionException, InterruptedException {
		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;
            //传入的两个参数: result:结果  exception:异常
        }, execute).whenComplete((result,exception) -> {
            //虽然可以感知异常信息。但是无法返回数据(类似于监听器)
            System.out.println("异步任务为执行成功......结果是:"+ result + ",异常是:"+ exception);
        }).exceptionally(throwable -> {
            //可以感知异常信息。同时可以返回默认值
            return 10;
        });
        System.out.println("返回值 = " + future.get()); //此处因为异常返回的是定义的异常返回默认值

        System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
当前线程:11
异步任务为执行成功......结果是:null,异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
返回值 = 10
main ... end ...

03、handle 方法 -> 最终处理


handle():可以对执行返回的结果进行进一步处理并返回自定义值

  • 示例
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
  	
  	/***
  	*	方法执行完成后的处理
  	*/
 	public static void main(String[] args) throws ExecutionException, InterruptedException {
      	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;
            //传入的两个参数: result:结果  thr:异常
        }, execute).handle((result,thr) -> {
            if (result != null){
                return result * 2;
            }
            if (thr != null){
                return 0;
            }
            return 1;
        });
        System.out.println("返回值 = " + future.get());

        System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
当前线程:11
返回值 = 0
main ... end ...

04、线程串行化


//不能接收上一步的执行结果,无返回值
public CompletableFuture<Void>  thenRun(Runnable action)
public CompletableFuture<Void>  thenRunAsync(Runnable action)
public CompletableFuture<Void>  thenRunAsync(Runnable action, Executor executor)
    
//能接收上一步结果,并消费处理该结果,无返回值
public CompletableFuture<Void>  thenAccept(Consumer<? super T> action)
public CompletableFuture<Void>  thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void>  thenAcceptAsync(Consumer<? super T> action, Executor executor)   
    
//能接收上一步结果,并消费处理该结果,有返回值
public <U> CompletableFuture<U>  thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U>  thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U>  thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
  • T:上一个任务返回结果的类型
  • U:当前任务的返回值类型
  • 带有Async默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。
  • 测试thenRun 不能接收上一步的执行结果,无返回值
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
      	System.out.println("main ... start ...");
		//串行化
    	CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
    		System.out.println("当前线程:" + Thread.currentThread().getId());
        	int i = 10 / 4;
        	System.out.println("运行结果:" + i);
        	return i;
 		}, execute).thenRunAsync(() -> {
        	System.out.println("任务2启动了......");
    	}, execute);
    	System.out.println("返回值 = " + future.get());
    	System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
返回值 = null  //无返回值
main ... end ...
  • 测试thenAccept 能接收上一步结果,并消费处理该结果,无返回值
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
      	System.out.println("main ... start ...");
		//串行化
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, execute).thenAcceptAsync((result) -> {
            System.out.println("任务2启动了......");
            System.out.println("result = " + result);
        }, execute);
    	System.out.println("返回值 = " + future.get());
    	System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
result = 2  //接收上一步的结果
返回值 = null  //无返回值
main ... end ...
  • 测试thenApply 能接收上一步结果,并消费处理该结果,有返回值
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
      	System.out.println("main ... start ...");
		//串行化
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("运行结果:" + i);
            return i;
        }, execute).thenApplyAsync((result) -> {
            System.out.println("任务2启动了......");
          	System.out.println("result = " + result);
            return "Hello" + result;
        }, execute);
    	System.out.println("返回值 = " + future.get());
    	System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
当前线程:11
运行结果:2
任务2启动了......
result = 2  //接收上一步的结果
返回值 = Hello2  //有返回值
main ... end ...

05、两任务组合 - 都要完成


以下方法的触发条件:--->之前的两个任务都完成,才开始执行合并任务。A&&B==1-->执行C的关系

//runAfterBoth:不获取future结果,没有返回值
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor executor);

//thenAcceptBoth:获取两个future任务的结果,没有返回值
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor);

//thenCombine:获取两个future任务的结果,有返回值
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
  • 示例
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
      	System.out.println("main ... start ...");
//任务1
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程启动...... 当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1线程结束...... 运行结果:" + i);
            return i;
        }, execute);
//任务2
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程启动...... 当前线程:" + Thread.currentThread().getId());
            System.out.println("任务2线程结束......");
            return "Hello";
        }, execute);
      	
//合并任务插入的位置..................
      	
        System.out.println("返回值 = " + future.get());
        System.out.println("main ... end ...");
    }
}
  • runAfterBoth:不获取future结果,没有返回值
        //合并任务1
        CompletableFuture<Void> future = future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务3开始......");
        }, execute);
  • 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始......
返回值 = null //没有返回值
main ... end ...
  • thenAcceptBoth:获取两个future任务的结果,没有返回值
        //合并任务2               f1 和 f2 分别是 future01 和 future02 的返回值
        CompletableFuture<Void> future = future01.thenAcceptBothAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始...... 接收的结果分别是:" + f1 +" --> " + f2);
        }, execute);
  • 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始...... 接收的结果分别是:2 --> Hello //接收前两个任务的结果
返回值 = null //没有返回值
main ... end ...
  • thenCombine:获取两个future任务的结果,有返回值
        //合并任务3               f1 和 f2 分别是 future01 和 future02 的返回值
        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
            System.out.println("任务3开始...... 接收的结果分别是:" + f1 + " --> " + f2);
            return f1 + " : " + f2;
        }, execute);
  • 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务2线程结束......
任务3开始...... 接收的结果分别是:2 --> Hello //接收前两个任务的结果
返回值 = 2 : Hello //有返回值
main ... end ...

06、两个任务组合 - 一个完成


以下方法的触发条件:--->之前的两个任务任意完成一个,就开始执行合并任务。A||B==1-->执行C的关系

//runAfterEither:不获取future结果,没有返回值
public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);

//acceptEither:获取完成了的那个future的结果,没有返回值
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action,Executor executor);

//applyToEither:获取完成了的那个future的结果,并且有返回值
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn,Executor executor);
  • 示例
  • 为了让示例效果明显,让任务2睡眠3s才执行任务2结束的语句
  • 注意方法1和方法2的返回值类型应该统一,此处都用Object
  • 接收返回值只接收一个,为执行完毕的那个方法的返回值
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程启动...... 当前线程:" + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("任务1线程结束...... 运行结果:" + i);
            return i;
        }, execute);
//任务2
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程启动...... 当前线程:" + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务2线程结束......");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }, execute);
      	
//合并任务插入的位置..................
      	
        System.out.println("返回值 = " + future.get());
        System.out.println("main ... end ...");
    }
}
  • runAfterEither:不获取future结果,没有返回值
        //合并任务1
        CompletableFuture<Void> future = future01.runAfterEitherAsync(future02, () -> {
            System.out.println("任务3开始......");
        }, execute);
  • 输出
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... //任务3提前执行
返回值 = null // 没有返回值
main ... end ...
任务2线程结束......
  • acceptEither:获取完成了的那个future的结果,没有返回值
        //合并任务2
        CompletableFuture<Void> future = future01.acceptEitherAsync(future02, (result) -> {
            System.out.println("任务3开始...... 执行完成的方法的结果是:" + result);
        }, execute);
  • 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... 执行完成的方法的结果是:2 //方法1先运行完毕,其返回值为2,且任务3提前执行
返回值 = null //没有返回值
main ... end ...
任务2线程结束......
  • applyToEither:获取完成了的那个future的结果,并且有返回值
        //合并任务3
        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (result) -> {
            System.out.println("任务3开始...... 执行完成的方法的结果是:" + result);
            return result.toString() + "--> 乌拉";
        }, execute);
  • 输出
main ... start ...
任务1线程启动...... 当前线程:11
任务1线程结束...... 运行结果:2
任务2线程启动...... 当前线程:12
任务3开始...... 执行完成的方法的结果是:2 //任务1先运行完毕,其返回值为2,且任务3提前执行
返回值 = 2--> 乌拉 //有返回值
main ... end ...
任务2线程结束......

07、多任务组合


//allOf:等待所有任务完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
    
//anyOf:只需要其中一个任务完成
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
  • 示例
  • 需要任务1、任务2、任务3 依次执行
  • 为了让示例效果明显,让任务2睡眠3s才执行打印语句
  • 记得一定要执行get()或join()方法
  • allOf:等待所有任务完成
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        },execute);
//任务2
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品的属性信息");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "黑色 256GB";
        },execute);
//任务3
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为 P40";
        },execute);
	
//多任务组合allOf()
      	CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        
        future.get(); //等待结果完成
//        future.join(); //使用join也可以
		
        System.out.println("之前任务的返回值 = " + futureImg.get() + " -> " + futureAttr.get() + " -> " + futureDesc.get());

        System.out.println("返回值 = " + future.get());
      
        System.out.println("main ... end ...");
    }
}
  • 输出结果
main ... start ...
查询商品的图片信息
查询商品的属性信息   //顺序执行
查询商品的介绍
之前任务的返回值 = hello.jpg -> 黑色 256GB -> 华为 P40 //可以获取之前任务的返回值
返回值 = null //方法返回值为空
main ... end ...

注意:不加get()或者join()的话,会发现执行顺序不对

在这里插入图片描述

  • anyOf:只需要其中一个任务完成
  • 不要去使用之前任务的返回值,因为get()是阻塞方法,会阻塞使得前3个任务都执行完成
public class ThreadTest {
	
    //创建一个固定数量的线程池 此处为创建10个
    public static ExecutorService execute = Executors.newFixedThreadPool(10);
	public static void main(String[] args) throws ExecutionException, InterruptedException {
//任务1
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        },execute);
//任务2
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询商品的属性信息");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "黑色 256GB";
        },execute);
//任务3
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为 P40";
        },execute);
      
//多任务组合anyof()
        CompletableFuture<Object> future = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
//        future.get(); //等待结果完成
//        future.join();

//        System.out.println("之前任务的返回值 = " + futureImg.get() + " -> " + futureAttr.get() + " -> " + futureDesc.get());  //这一行不要用了

        System.out.println("返回值 = " + future.get());
        System.out.println("main ... end ...");
    }
}
  • 输出
main ... start ...
查询商品的图片信息   //第一个任务执行后,后面的任务就不需要执行了
返回值 = hello.jpg //返回最先执行任务的返回值
main ... end ...
查询商品的介绍
查询商品的属性信息
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值