线程与异步编排

线程基础

初始化线程的四种方式
  1. 继承 Thread 类

    public static void main(String[] args) {
    
        System.out.println("main....start....");
        Thread01 thread01 = new Thread01();
        thread01.start();
        System.out.println("mai....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);
        }
    }
    
  2. 实现 Runnable 接口

    public static void main(String[] args) {
    
        System.out.println("main....start....");
        Runnable01 runnable01 = new Runnable01();
        new Thread(runnable01).start();
        System.out.println("mai....end....");
    }
    
    public static class Runnable01 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 void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable01());
        new Thread(integerFutureTask).start();
        // 等待线程执行完成,拿到异步执行的结果
        Integer integer = integerFutureTask.get();
        System.out.println(integer);
    }
    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;
        }
    }
    
  4. 给线程池直接提交任务

    public static ExecutorService service = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        service.execute(new Runnable01());
        System.out.println("main...end....");
    }
    public static class Runnable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
        }
    }
    
线程池的七大参数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) ;

运行流程:

  1. 线程池创建,准备好 corePoolSize 数量的核心线程,准备接受任务
  2. 新的任务进来,用 corePoolSize 中的空闲线程执行。
  3. 当corePoolSize 数量的线程没有空闲,都在运行时。再次进来的任务将会景区阻塞队列中。一旦corePoolSize中有空闲的线程时,就会取到阻塞队列中的任务,然后执行任务。
  4. 当阻塞队列满了以后,就会直接开新的线程执行。最大能开到 maximumPoolSize指定数量的线程。
  5. 如果 maximumPoolSize 都执行完成了任务,并且现在处于空闲状态了,那么 会在 keepAliveTime 时间内,将 maximumPoolSize 数量的线程,减少到 corePoolSize 数量。
  6. 如果线程数到了 maximumPoolSize后,还有新任务进来,得不到执行,那么这些任务将会被指定的拒绝策略 RejectedExecutionHandler 拒绝。
  7. 所有的线程创建,都是由指定的 ThreadFactory 创建的。

题目:一个线程池 corePoolSize = 7, maximumPoolSize = 20, workQueue = 50,如果100并发进来怎么分配。

首先 7 个线程执行任务,此时还有任务,就需要用阻塞队列接收任务 50 个任务,还有任务没有得到执行,此时,需要将线程数增加到 20 个,一共 20 个线程执行任务,50 个任务放在阻塞队列中。剩下的30任务得不到执行,采用默认的拒绝策略。

常见的 4 四种线程池
  • Executors.newCachedThreadPool()

    public static ExecutorService newCachedThreadPool() {
      return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                    60L, TimeUnit.SECONDS,
                                    new SynchronousQueue<Runnable>());
    }
    

    SynchronousQueue是无界的,是一种无缓冲的等待队列,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加;可以认为SynchronousQueue是一个缓存值为1的阻塞队列,但是 isEmpty()方法永远返回是true,remainingCapacity() 方法永远返回是0,remove()和removeAll() 方法永远返回是false,iterator()方法永远返回空,peek()方法永远返回null。

  • Executors.newFixedThreadPool() 创建的线程池有固定数量的线程。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    

    LinkedBlockingQueue内部由单链表实现,只能从head取元素,从tail添加元素。添加元素和获取元素都有独立的锁,也就是说LinkedBlockingQueue是读写分离的,读写操作可以并行执行。LinkedBlockingQueue采用可重入锁(ReentrantLock)来保证在并发情况下的线程安全。

    LinkedBlockingQueue是一个阻塞队列,内部由两个ReentrantLock来实现出入队列的线程安全,由各自的Condition对象的await和signal来实现等待和唤醒功能。它和ArrayBlockingQueue的不同点在于:

    1. 队列大小有所不同,ArrayBlockingQueue是有界的初始化必须指定大小,而LinkedBlockingQueue可以是有界的也可以是无界的(Integer.MAX_VALUE),对于后者而言,当添加速度大于移除速度时,在无界的情况下,可能会造成内存溢出等问题。
    2. 数据存储容器不同,ArrayBlockingQueue采用的是数组作为数据存储容器,而LinkedBlockingQueue采用的则是以Node节点作为连接对象的链表。
    3. 由于ArrayBlockingQueue采用的是数组的存储容器,因此在插入或删除元素时不会产生或销毁任何额外的对象实例,而LinkedBlockingQueue则会生成一个额外的Node对象。这可能在长时间内需要高效并发地处理大批量数据的时,对于GC可能存在较大影响。
    4. 两者的实现队列添加或移除的锁不一样,ArrayBlockingQueue实现的队列中的锁是没有分离的,即添加操作和移除操作采用的同一个ReenterLock锁,而LinkedBlockingQueue实现的队列中的锁是分离的,其添加采用的是putLock,移除采用的则是takeLock,这样能大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
  • Executors.newScheduledThreadPool()

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
       return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
       super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
             new DelayedWorkQueue());
    }
    

    DelayedWorkQueue

    队列是先进先出的数据结构,就是先进入队列的数据,先被获取。但是有一种特殊的队列叫做优先级队列,它会对插入的数据进行优先级排序,保证优先级越高的数据首先被获取,与数据的插入顺序无关。实现优先级队列高效常用的一种方式就是使用堆。

  • Executors.newSingleThreadExecutor()

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    

    线程池容量大小为1,单线程线程池。用一个线程执行任务,其它任务在无界队列中排队等待。

使用线程池的优势
  1. 降低资源消耗:通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
  2. 提高响应速度:因为线程池中的执行任务的线程数没有超过线程池的最大上限时,有些线程处于等待分配任务的状态。当任务来时无需创建线程就能被执行。
  3. 提高线程的可管理性:线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。因为无限的创建和销毁线程不仅消耗系统资源,还降低了系统的稳定性。

线程异步编排 CompletableFuture

线程的异步执行以及返回结果
  1. runAsync,异步运行

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture.runAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
        }, executorService);
        System.out.println("main...end....");
    }
    
  2. supplyAsync 异步执行,并且有返回值

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
        Integer integer = integerCompletableFuture.get(); // 阻塞调用,获取到返回值
        System.out.println("获取到异步县城的返回值" + integer);
        System.out.println("main...end....");
    }
    
  3. whenComplete 异步执行完成后,执行回调方法

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            System.out.println("main...start....");
            System.out.println("当前线程main - id:" + Thread.currentThread().getId());
            CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
                int i = 10 / 2;
                System.out.println("运行结果: " + i);
                return i;
            }, executorService).whenComplete((result, exception) -> {
                System.out.println("当前线程Complete - id:" + Thread.currentThread().getId());
                System.out.println("结果是:" + result + ",异常是:" + exception);
            });
            System.out.println("main...end....");
    
    }
    

    运行结果1:

    main…start…
    当前线程main - id:1
    main…end…
    当前线程supplyAsync - id:12
    运行结果: 5
    当前线程Complete - id:12
    结果是:5,异常是:null

    运行结果2:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    当前线程Complete - id:1
    结果是:5,异常是:null
    main…end…

    结论:执行 whenComplete 线程可能是主线程,也可能是运行 supplyAsync 方法的线程。

  4. whenCompleteAsync 以不同的线程执行回调任务

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            System.out.println("main...start....");
            System.out.println("当前线程main - id:" + Thread.currentThread().getId());
            CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
                int i = 10 / 2;
                System.out.println("运行结果: " + i);
                return i;
            }, executorService).whenCompleteAsync((result, exception) -> {
                System.out.println("当前线程Complete - id:" + Thread.currentThread().getId());
                System.out.println("结果是:" + result + ",异常是:" + exception);
            }, executorService);
            System.out.println("main...end....");
    
    }
    

    whenCompleteAsync 以不同的线程,执行回调方法。

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    main…end…
    当前线程Complete - id:13
    结果是:5,异常是:null

  5. exceptionally 异常处理,虽然 whenComplete 和 whenCompleteAsync 也可以处理异常,但是 exceptionally 也可以处理异常,并且返回特定值。只有出现异常时,该方法 exceptionally 才会被执行。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService).whenCompleteAsync((result, exception) -> {
            System.out.println("当前线程Complete - id:" + Thread.currentThread().getId());
            System.out.println("结果是:" + result + ",异常是:" + exception);
        }, executorService).exceptionally((t) -> {
            System.out.println("当前线程exceptionally - id:" + Thread.currentThread().getId());
            System.out.println("exceptionally 捕获到了异常: " + t.getMessage());
            return 10; //返回特定值
        });
    
        Integer integer = integerCompletableFuture.get();
        System.out.println("获取到异步任务执行的结果" + integer);
        System.out.println("main...end....");
        System.out.println();
    
    }
    

    执行的结果:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:14
    当前线程Complete - id:15
    结果是:null,异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
    当前线程exceptionally - id:15
    exceptionally 捕获到了异常: java.lang.ArithmeticException: / by zero
    获取到异步任务执行的结果10
    main…end…

    需要注意:执行 exceptionally方法 的线程,可能来自于线程池,也可能不是线程池中的线程。

  6. handle 和 handleAsync 方法,既可以得到正确执行时候的处理结果,也可以得到任务执行时候出现的异常,并且能够对结果进行处理后返回。相当于结合了 whenCompleteAsync/whenComplete 和 exceptionally 这两个方法的功能。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        for (int j = 1; j < 100; ++j) {
            System.out.println("main...start....");
            System.out.println("当前线程main - id:" + Thread.currentThread().getId());
            CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
                System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
                int i = 10 / 2;
                System.out.println("运行结果: " + i);
                return i;
            }, executorService).handleAsync((result, exception) -> {
                System.out.println("当前线程 handle - id:" + Thread.currentThread().getId());
                if (exception == null) {
                    return 10;
                } else {
                    return 3;
                }
            }, executorService);
            Integer integer = integerCompletableFuture.get();
            System.out.println("获取到异步任务执行的结果" + integer);
            System.out.println("main...end....");
            System.out.println();
        }
    }
    

    输出的部分结果:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    当前线程 handle - id:13
    获取到异步任务执行的结果10
    main…end…

线程的串行化
  1. thenRun/thenRunAsync 方法,当上一个任务执行完成时,执行当前任务。thenRun里执行的任务,感知不到上一个任务的返回值,并且执行完成当前任务,也没有返回值。

     public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
     public static void main(String[] args) throws ExecutionException, InterruptedException {
    
         System.out.println("main...start....");
         System.out.println("当前线程main - id:" + Thread.currentThread().getId());
         CompletableFuture.supplyAsync(() -> {
             System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
             int i = 10 / 2;
             System.out.println("运行结果: " + i);
             return i;
         }, executorService).thenRunAsync(() -> {
             System.out.println("当前线程thenRunAsync - id:" + Thread.currentThread().getId());
             System.out.println("执行任务2");
         }, executorService);
         System.out.println("main...end....");
     }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    main…end…
    当前线程thenRunAsync - id:13
    执行任务2

  2. thenAccept/thenAcceptAsync 方法,当上一个任务执行完成时候,可以获取到任务的返回结果,在当前线程中进行处理,但是无法感知上一个任务的异常。(与whenComplete 有些区别)

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService).thenAcceptAsync((t) -> {
            System.out.println("当前线程thenRunAsync - id:" + Thread.currentThread().getId());
            System.out.println("执行任务2,获取到任务1的返回结果:" + t);
        }, executorService);
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    main…end…
    当前线程thenRunAsync - id:13
    执行任务2,获取到任务1的返回结果:5

  3. thenApply/thenApplyAsync 方法,获取到上一个任务执行后的结果,并且返回当前任务的结果。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService).thenApplyAsync((t) -> {
            System.out.println("当前线程thenRunAsync - id:" + Thread.currentThread().getId());
            System.out.println("执行任务2,获取到任务1的返回结果:" + t);
            return 10;
        }, executorService);
        Integer integer = integerCompletableFuture.get();
        System.out.println("获取到任务的执行结果:" + integer);
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前线程supplyAsync - id:12
    运行结果: 5
    当前线程thenRunAsync - id:13
    执行任务2,获取到任务1的返回结果:5
    获取到任务的执行结果:10
    main…end…

两任务组合 - 两个都要完成
  1. runAfterBoth / runAfterBothAsync 当两个任务都执行完成时,才执行第三个任务。而第三个任务无法获取到前两个任务的返回结果。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "hello";
        }, executorService);
    
        integerCompletableFuture.runAfterBothAsync(stringCompletableFuture, ()-> {
            System.out.println("任务1和任务2已经执行完成,现在执行任务3");
        }, executorService);
    
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    main…end…
    任务1和任务2已经执行完成,现在执行任务3

  2. thenAcceptBoth/thenAcceptBothAsync 方法,执行当前任务时,可以获取前两个任务的返回结果,但是当前没有返回值。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "hello";
        }, executorService);
    
        integerCompletableFuture.thenAcceptBothAsync(stringCompletableFuture, (result1, result2)-> {
            System.out.println("任务1和任务2已经执行完成,现在执行任务3");
            System.out.println("获取到任务1的返回结果:" + result1);
            System.out.println("获取到任务2的返回结果:" + result2);
        }, executorService);
    
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    main…end…
    任务1和任务2已经执行完成,现在执行任务3
    获取到任务1的返回结果:5
    获取到任务2的返回结果:hello

  3. thenCombine/thenCombineAsync 执行当前任务,获取到任务1和任务2的返回结果,并且返回当前任务的执行结果。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "hello";
        }, executorService);
    
        CompletableFuture<Integer> integerCompletableFuture1 = integerCompletableFuture.thenCombineAsync(stringCompletableFuture, (result1, result2) -> {
            System.out.println("任务1和任务2已经执行完成,现在执行任务3");
            System.out.println("获取到任务1的返回结果:" + result1);
            System.out.println("获取到任务2的返回结果:" + result2);
            return 30;
        }, executorService);
    
        Integer integer = integerCompletableFuture1.get();
        System.out.println("获取到任务3的执行结果:" + integer);
    
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    任务1和任务2已经执行完成,现在执行任务3
    获取到任务1的返回结果:5
    获取到任务2的返回结果:hello
    获取到任务3的执行结果:30
    main…end…

两任务组合 - 只要其中一个完成
  1. runAfterEither/runAfterEitherAsync 两个任务其中一个执行完成,执行当前任务。获取不到前两个任务其中之一的返回值,当前也没有返回值

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "hello";
        }, executorService);
    
        integerCompletableFuture.runAfterEitherAsync(stringCompletableFuture, () -> {
            System.out.println("执行第三个任务");
        }, executorService);
        
        System.out.println("main...end....");
    }
    

    运行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    main…end…
    执行第三个任务
    当前任务2线程supplyAsync - id:13

    从运行的结果中可以看出,当执行第三个任务时,只有任务1执行完成,而任务2还没有执行完成。

  2. acceptEither/acceptEitherAsync 当前两个任务其中之一执行完成时,执行当前任务。当前任务可以获取到前面执行完成的任务的返回值。当前任务没有返回值。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
         System.out.println("main...start....");
         System.out.println("当前线程main - id:" + Thread.currentThread().getId());
         // 任务1
         CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
             System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
             int i = 10 / 2;
             System.out.println("运行结果: " + i);
             return i;
         }, executorService);
    
         // 任务2
         CompletableFuture<Integer> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
             System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
             return 1;
         }, executorService);
    
         integerCompletableFuture.acceptEitherAsync(stringCompletableFuture, (t) -> {
             System.out.println("执行第三个任务");
             System.out.println("获取到前面两个任务其中之一的执行结果:" + t);
         }, executorService);
    
         System.out.println("main...end....");
     }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    main…end…
    执行第三个任务
    获取到前面两个任务其中之一的执行结果:5

  3. applyToEither/applyToEitherAsync 当前两个任务其中之一执行完成时,执行当前任务。当前任务可以获取到前面执行完成的任务的返回值。当前任务有返回值。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<Integer> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return 1;
        }, executorService);
    
        CompletableFuture<String> hello = integerCompletableFuture.applyToEitherAsync(stringCompletableFuture, (t) -> {
            System.out.println("执行第三个任务");
            System.out.println("获取到前面两个任务其中之一的执行结果:" + t);
            return "hello";
        }, executorService);
        
        String s = hello.get();
        System.out.println("第三个任务的返回值:" + s);
        System.out.println("main...end....");
    }
    

    运行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    执行第三个任务
    获取到前面两个任务其中之一的执行结果:5
    第三个任务的返回值:hello
    main…end…

多任务组合
  1. allOf 等待所有任务执行完成后,执行其它任务。

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "Hello World";
        }, executorService);
    
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(integerCompletableFuture, stringCompletableFuture);
        voidCompletableFuture.get();
    
        System.out.println("来到这里,表明前两个异步任务都已经执行完成了");
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    当前任务2线程supplyAsync - id:13
    来到这里,表明前两个异步任务都已经执行完成了
    main…end…

  2. anyOf 只要其中一个任务执行执行完成即可

    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        System.out.println("main...start....");
        System.out.println("当前线程main - id:" + Thread.currentThread().getId());
        // 任务1
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务1线程supplyAsync - id:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executorService);
    
        // 任务2
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前任务2线程supplyAsync - id:" + Thread.currentThread().getId());
            return "Hello World";
        }, executorService);
    
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(integerCompletableFuture, stringCompletableFuture);
        Object o = objectCompletableFuture.get();
    
        System.out.println("来到这里,表明前两个任务其中之一已经执行完成,并且有返回值" + o);
        System.out.println("main...end....");
    }
    

    执行结果:

    main…start…
    当前线程main - id:1
    当前任务1线程supplyAsync - id:12
    运行结果: 5
    来到这里,表明前两个任务其中之一已经执行完成,并且有返回值5
    main…end…
    当前任务2线程supplyAsync - id:13

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值