异步CompletableFuture线程

tips:解释下主线程等待,子线程执行,如果子线程发生异常会被捕捉,主线程也会发生异常而终止,不会一直阻塞下去

        ExecutorService executorService= Executors.newSingleThreadExecutor();
        Future<Double> cf = executorService.submit(()->{
            System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }


            if(false){//改成ture后就抛异常了,cf.get()也不会一直阻塞主线程
                throw new RuntimeException("test");
            }else{
                System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
                return 1.2;
            }
        });
        System.out.println("run result->"+cf.get());

 

supplyAsync异步带有返回值

 

   CompletableFuture completableFuture= CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
                System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
                return "我是返回值";
            
        });
        System.out.println("completableFuture result->"+completableFuture.get());

 

runAsync异步没有返回值

 

        CompletableFuture cf = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            if(false){
                throw new RuntimeException("test");
            }else{
                System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
            }
        });
        System.out.println("main thread start,time->"+System.currentTimeMillis());
        //等待子任务执行完成
        System.out.println("run result->"+cf.get());

 

CompletableFuture里面执行的其实还是Executor的实现类,默认执行的是ForkJoinPool
源码如下:
   public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

   static Executor screenExecutor(Executor e) {
        if (!useCommonPool && e == ForkJoinPool.commonPool())//这里是ForfJoinPool
            return asyncPool;
        if (e == null) throw new NullPointerException();
        return e;
    }

如果是机器是单核的,就会创建一个ThreadPerTaskExecutor的执行器:
源码如下:

    private static final boolean useCommonPool =
        (ForkJoinPool.getCommonPoolParallelism() > 1);//判断单核多核返回boolean值


    private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool()
 : new ThreadPerTaskExecutor();//单核就new一个执行器

ThreadPerTaskExecutor 实现Executor接口并且创建一个单线程
 static final class ThreadPerTaskExecutor implements Executor {
        public void execute(Runnable r) { new Thread(r).start(); }
    }

 

基于上述源码可以看到CompletableFuture应该有两个重载Executor的方法
于是乎有如下静态构造方法:
   public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

         /111111111111111111111111111
        ForkJoinPool forkJoinPool=new ForkJoinPool();
         CompletableFuture completableFuture=CompletableFuture.supplyAsync(()->{
              //do yourself
                return xxxxx;
        
        },forkJoinPool);
     System.out.println("completableFuture result->"+completableFuture.get());


           /22222222222
        ExecutorService executorService= Executors.newSingleThreadExecutor();
        // 创建异步执行任务:
        CompletableFuture cf = CompletableFuture.runAsync(()->{
           //do yourself
        },executorService);
        System.out.println("main thread start,time->"+System.currentTimeMillis());
        //等待子任务执行完成
        System.out.println("run result->"+cf.get());

 

异步回调
1、thenApply:表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中
2.thenApplyAsync

 

      ForkJoinPool pool=new ForkJoinPool();
        // 创建异步执行任务:
        CompletableFuture cf = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread()+" 任务一,开始time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread()+" 任务一,结束time->"+System.currentTimeMillis());

            return "123456789";
        },pool);
        Object o = cf.get();
        System.out.println(o);

        CompletableFuture completableFuture = cf.thenApplyAsync((result)->{
            System.out.println(Thread.currentThread()+" 任务二,开始time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread()+" 任务二,结束time->"+System.currentTimeMillis());
            return "456789123"+result;
        });
        System.out.println("main thread start cf.get(),time->"+System.currentTimeMillis());
        System.out.println(completableFuture.get());
        pool.shutdown();

 

thenAccept:接收上一个任务的执行结果作为入参,但是没有返回值
thenRun:没入参也没返回值

 

        ForkJoinPool pool=new ForkJoinPool();
        // 创建异步执行任务:
        CompletableFuture cf = CompletableFuture.supplyAsync(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "123";
        },pool);

        CompletableFuture completableFuture = cf.thenApply((result)->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "456";
        }).thenAccept((result)->{//接收上一个任务的执行结果作为入参,但是没有返回值
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("接收:"+result);
        }).thenRun(()->{//没入参也没返回值
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("啥也不干");
        });
        System.out.println(":::::::"+cf.get());
        System.out.println("等待最后一个thenRun执行完成completableFuture才输出:"+completableFuture.get());

 

 

  exceptionally方法指定某个任务执行异常时执行的回调方法,
会将抛出异常作为参数传递到回调方法中,
如果该任务正常执行,exceptionally
方法返回的CompletionStage的result就是该任务正常执行的结果( CompletableFuture<T> implements Future<T>, CompletionStage<T>)

 

        ForkJoinPool pool=new ForkJoinPool();
        // 创建异步执行任务:
        CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
            System.out.println("任务一");
            if(true){
                throw new RuntimeException("test");
            }else{
                return 1.23;
            }
        },pool);
        //cf执行异常时,将抛出的异常作为入参传递给回调方法
        CompletableFuture<Double> cf2= cf.exceptionally((param)->{
            System.out.println("任务二");
            System.out.println("error stack trace->");
            param.printStackTrace();
            System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
            return -1.0;
        });
        //cf正常执行时执行的逻辑,如果执行异常则不调用此逻辑
        CompletableFuture cf3=cf.thenAccept((param)->{
            System.out.println("任务三");
            System.out.println("param->"+param);
        });
        //等待子任务执行完成,此处无论是任务二和任务三都可以实现job2退出,主线程才退出
        // 如果是cf,则主线程不会等待任务二执行完成自动退出了
        //cf2.get时,没有异常,但是依然有返回值,就是cf的返回值
        System.out.println("》》》》》》》》》》->"+cf2.get());

 等一组线程完成输出结果

package org.wangbiao.es.restclient.util;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Data
@Slf4j
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyElement {
    private String name;
    private Integer result;

    public static void main(String[] args) {
        List<MyElement> elementList = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            elementList.add(MyElement.builder().result(i).name(i + "0000000").build());
        }
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        for (int i = 0; i < elementList.size(); i++) {
            final int index = i;
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                // 这里模拟一个异步执行的任务,比如进行一些计算等,返回一个结果
                int result = performTask(elementList.get(index));
                elementList.get(index).setResult(result);
                return null;
            });
            futures.add(future);
        }

        // 等待所有的CompletableFuture都执行完成
//        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        // 输出每个元素以及对应的结果
        for (MyElement element : elementList) {
            System.out.println("元素: " + element.getName() + ", 结果: " + element.getResult());
        }
    }

    private static int performTask(MyElement ele) {
        // 这里可以替换为真实的、根据元素不同而执行不同逻辑的任务,这里简单返回一个和元素名称相关的数值作为示例
        return ele.getResult() + 1;
    }
}

 

posted @ 2022-04-11 16:01  余生请多指教ANT  阅读(69)  评论(0)    收藏  举报