JAVA异步编程-JDK-CompletableFuture实践与原理

5 篇文章 0 订阅
4 篇文章 0 订阅

1.文章目录

  • ComPletableFuture概述
  • CompletableFuture实践
  • CompletableFuture主要源码导读

2.CompletableFuture概述

  • CompleatableFuture是对Future的增强,我们知道Future的局限性,CompleatableFuture可以通过编程方式显式设置计算结果和状态,并且可以作为一个计算阶段,当他完成时还能触发另一个函数/行为;
  • 当多个线程调用CompletableFuture的complete,cancel方式只有一个线程会成功;
  • CompletableFuture实现了CompletionStage接口方法:主要是当CompletableFuture任务结束后,同步使用任务来执行依赖任务结果的函数/行为
  • 所有异步的方法在没有执行Executor参数情况下,都是用ForkJoinPool.commonPool线程池来执行;
  • 所有实现CompletionStage的方法都是相互独立的实现,不会因为重载其他方法影响;
  • 另外:CompletableFuture的结果有一些任务依赖于此,利用的无锁栈结构(CAS实现),因此执行顺序和依赖顺序相反;

3.CompletableFuture实践

显式设置CompletableFuture结果


public class CompletableFutureTest {
    // 自定义线程池
    private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] argv) throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = new CompletableFuture<String>();
        POOL_EXECUTOR.execute(()->{
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        // 设置future结果
        System.out.println("---" + Thread.currentThread().getName() + " set future result --- ");
        completableFuture.complete("niuBi");

        // 等待异步执行结果
        System.out.println("main wait future result");
        System.out.println(completableFuture.get());
        System.out.println("main get future result");

        // 关闭线程池
        POOL_EXECUTOR.shutdown();
    }
}
  • 创建线程池,提交任务到异步线程池,主线程调用get等待线程执行完任务,会阻塞主线程;

基于CompletableFuture实现异步计算与结果转化

  • 基于runAsync系列方法实现无返回值的异步计算;
  • 异步打印日志,Dubbo异步存放配置信息,异步消息通知等模型
public class CompletableFutureTest {
    
    public static void runAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("over");
            }
        });

        System.out.println(completableFuture.get());
    }
    public static void main(String[] argv) throws ExecutionException, InterruptedException {
       runAsync();
    }
}
  • future.get获取的是null,我们知道默认是ForkJoinPool.commonPool线程池,我们也可以自己实现线程池;
public class CompletableFutureTest {
    // 自定义线程池
    private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());


    public static void runAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("over");
            }
        }, POOL_EXECUTOR);

        System.out.println(completableFuture.get());
    }
    public static void main(String[] argv) throws ExecutionException, InterruptedException {

       runAsync();
    }
}
  • 基于supplyAsync系列方法实现有返回值的异步计算
  • future.get返回"niuBi",也可以转化为自定义线程池执行异步任务
public static void supplyAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 返回异步计算
                return "niuBi";
            }
        });

        System.out.println(completableFuture.get());
    }

自定义线程池:完成有返回值异步计算

public class CompletableFutureTest {
    // 自定义线程池
    private final static int CPU_COUNT = Runtime.getRuntime().availableProcessors();

    private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(CPU_COUNT, 2 * CPU_COUNT, 1,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());


  
    public static void supplyAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 返回异步计算
                return "niuBi";
            }
        }, POOL_EXECUTOR);

        System.out.println(completableFuture.get());
    }
    public static void main(String[] argv) throws ExecutionException, InterruptedException {

       supplyAsync();
       POOL_EXECUTOR.shutdown();
    }
}
  • 基于thenRun实现异步任务A,执行完毕后,激活任务B,这种方式激活的异步任务B拿不到任务A的执行结果;
public static void thenRun() throws ExecutionException, InterruptedException {
        CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("one future end");
                // 返回异步结果
                return "hello, NiuBi";
            }
        });
        CompletableFuture<Void> twoFuture = oneFuture.thenRun(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("two Future end");
        });
        // 同步等待twoFuture结束
        System.out.println(twoFuture.get());
    }
  • 基于thenAccept实现异步任务A,执行完后,激活任务B,B获取A的结果搞事情;
  • future.get的结果为null;
public static void thenAccept() throws ExecutionException, InterruptedException {
        CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("one future end");

                return "niuBi";
            }
        });
        CompletableFuture<Void> twoFuture = oneFuture.thenAccept(new Consumer<String>() {
            @Override
            public void accept(String result) {
                // 对oneFuture的结果操作
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("two future get one future result : " + result + " add ");
            }
        });

        System.out.println(twoFuture.get());
    }
  • 基于thenApply实现任务A,完成后,激活任务B执行,B可以拿到A的结果,并且我们可以获得B的结果
  • 默认的oneFuture以及回调事件twoFuture在ForkJoin线程池是同一线程,如果用自定义线程池,调度的线程可能不一样;

    public static void thenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("one future end");

                return "niuBi";
            }
        });

        CompletableFuture<String> twoFuture = oneFuture.thenApply(
                // arg1:前任务的返回结果类型,arg2:回调函数的返回类型
                new Function<String, String>() {
            @Override
            public String apply(String preResult) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return preResult + " two future add";
            }
        });

        System.out.println(twoFuture.get());
    }
  • 基于whenComplete设置回调函数:当异步任务执行完毕后进行回调,不会阻塞调用线程;
public class CompletableFutureTestDubbo {

    private static final CountDownLatch  countDownLatch = new CountDownLatch(1);
    public static void main(String[] argv) throws InterruptedException {
        CompletableFuture<String> oneFuture = CompletableFuture.supplyAsync(new Supplier<String>() {

            @Override
            public String get() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
                return "niuBi";
            }
        });

        oneFuture.whenComplete(new BiConsumer<String, Throwable>() {
            @Override
            public void accept(String s, Throwable throwable) {
                // 如果没有异常
                if (null == throwable){
                    System.out.println(s);
                } else {
                    throwable.printStackTrace();
                }
            }
        });

        countDownLatch.await();
    }
}
  • 多个CompletableFuture进行组合运算
  • 基于thenCompose实现当一个CompletableFuture执行完毕,执行另一个CompletableFuture
public class CompletableFutureTestDubbo {

    private static final CountDownLatch  countDownLatch = new CountDownLatch(1);
    public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return encodedCompanyId;
            }
        });
    }

    public static CompletableFuture<String> doSomethingTwo(String companyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return companyId + "阿里云";
            }
        });
    }
    public static void main(String[] argv) throws InterruptedException, ExecutionException {
        CompletableFuture<String> completableFuture = doSomethingOne("123").thenCompose(id -> doSomethingTwo(id));
        System.out.println(completableFuture.get());
    }
}
  • 基于thenCombine实现:两个并发任务结束,使用两者的结果作为参数;
public class CompletableFutureTestDubbo {

    private static final CountDownLatch  countDownLatch = new CountDownLatch(1);
    public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return encodedCompanyId;
            }
        });
    }

    public static CompletableFuture<String> doSomethingTwo(String companyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return companyId + "阿里云";
            }
        });
    }
    public static void main(String[] argv) throws InterruptedException, ExecutionException {
      
        CompletableFuture<Object> completableFuture = doSomethingOne("123").thenCombine(doSomethingTwo("456"), (oneResult, twoResult) -> {
                return oneResult + ":" + twoResult;
        });
        System.out.println(completableFuture.get());
    }
}
  • 基于AllOf等待所有并发任务结束
public class CompletableFutureTestDubbo {

    private static final CountDownLatch  countDownLatch = new CountDownLatch(1);
    public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("do SomethingOne");
                return encodedCompanyId;
            }
        });
    }

    public static CompletableFuture<String> doSomethingTwo(String companyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("do SomethingTwo");
                return companyId + "阿里云";
            }
        });
    }
    public static void main(String[] argv) throws InterruptedException, ExecutionException {
    
        List<CompletableFuture<String>> futureList = new ArrayList<>();
        futureList.add(doSomethingOne("111"));
        futureList.add(doSomethingOne("222"));
        futureList.add(doSomethingOne("333"));
        futureList.add(doSomethingTwo("444"));
        futureList.add(doSomethingTwo("555"));
        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[futureList.size()]));
        System.out.println(completableFuture.get());
    }
}
  • 基于anyof实现当任务集合中一个任务结束就会返回,但是任务都会运行完;
public class CompletableFutureTestDubbo {

    private static final CountDownLatch  countDownLatch = new CountDownLatch(1);
    public static CompletableFuture<String> doSomethingOne(String encodedCompanyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("do SomethingOne");
                return encodedCompanyId;
            }
        });
    }

    public static CompletableFuture<String> doSomethingTwo(String companyId){
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("do SomethingTwo");
                return companyId + "阿里云";
            }
        });
    }
    public static void main(String[] argv) throws InterruptedException, ExecutionException {
   
        List<CompletableFuture<String>> futureList = new ArrayList<>();
        futureList.add(doSomethingOne("111"));
        futureList.add(doSomethingOne("222"));
        futureList.add(doSomethingOne("333"));
        futureList.add(doSomethingTwo("444"));
        futureList.add(doSomethingTwo("555"));
        CompletableFuture<Object> completableFuture = CompletableFuture.anyOf(futureList.toArray(new CompletableFuture[futureList.size()]));
        System.out.println(completableFuture.get());
    }

异常处理

  • 当任务的处理过程出现异常,如何处理;
  • 如下代码,我们抛出异常,导致future.get一直阻塞,线上操作是致命的;
public class CompletableFutureExpectionTest {
    public static void main(String[] argv) throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = new CompletableFuture<>();
        new Thread(()->{
            try {
                if (true){
                    throw new RuntimeException("error cause");
                }
                completableFuture.complete("success");
            }catch (Exception e) {

            }
            System.out.println(Thread.currentThread().getName() + " set result");
        }, "threadA").start();

        System.out.println(completableFuture.get());
    }
}
  • completeExceptionAlly方法处理异常情况:如下代码,会打印异常信息
public class CompletableFutureExpectionTest {
    public static void main(String[] argv) throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = new CompletableFuture<>();
        new Thread(()->{
            try {
                if (true){
                    throw new RuntimeException("error cause");
                }
                completableFuture.complete("success");
            }catch (Exception e) {
                completableFuture.completeExceptionally(e);
            }
            System.out.println(Thread.currentThread().getName() + " set result");
        }, "threadA").start();

        //System.out.println(completableFuture.exceptionally(t-> "defalut").get());
         System.out.println(completableFuture.get());
    }
}
  • 以上是对于CompletableFuture的实践,具体业务可以更加灵活的扩展,结合应用;

4.CompletableFuture源码导读

基本属性:保存变量偏移量,CAS操作修改;

// Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long RESULT;
    private static final long STACK;
    private static final long NEXT;
    static {
        try {
            final sun.misc.Unsafe u;
            UNSAFE = u = sun.misc.Unsafe.getUnsafe();
            Class<?> k = CompletableFuture.class;
            RESULT = u.objectFieldOffset(k.getDeclaredField("result"));
            STACK = u.objectFieldOffset(k.getDeclaredField("stack"));
            NEXT = u.objectFieldOffset
                (Completion.class.getDeclaredField("next"));
        } catch (Exception x) {
            throw new Error(x);
        }
    }

reportget

 private static <T> T reportGet(Object r)
        throws InterruptedException, ExecutionException {
         // 如果r为null则抛出异常
        if (r == null) // by convention below, null means interrupted
            throw new InterruptedException();
        // 如果是异常类
        if (r instanceof AltResult) {
            Throwable x, cause;
            // 根据异常类型,抛出异常
            if ((x = ((AltResult)r).ex) == null)
                return null;
            if (x instanceof CancellationException)
                throw (CancellationException)x;
            if ((x instanceof CompletionException) &&
                (cause = x.getCause()) != null)
                x = cause;
            throw new ExecutionException(x);
        }
        // 转化结果
        @SuppressWarnings("unchecked") T t = (T) r;
        return t;
    }

线程池,Task运行本质

 // 默认为forkjoinPool  
private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

    // Task本质,创建线程运行

    static final class ThreadPerTaskExecutor implements Executor {
        public void execute(Runnable r) { new Thread(r).start(); }
    }

Completion代表一个异步计算节点

abstract static class Completion extends ForkJoinTask<Void>
        implements Runnable, AsynchronousCompletionTask {
       // 节点链
        volatile Completion next;      // Treiber stack link

       
        abstract CompletableFuture<?> tryFire(int mode);

        /** Returns true if possibly still triggerable. Used by cleanStack. */
        abstract boolean isLive();
        //task的运行,其实就是方法中写的run任务
        public final void run()                { tryFire(ASYNC); }
        public final boolean exec()            { tryFire(ASYNC); return true; }
        public final Void getRawResult()       { return null; }
        public final void setRawResult(Void v) {}
    }

runAsync(Runnable runnable):

 public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable);
    }

  static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
        // 判空校验
        if (f == null) throw new NullPointerException();
        // 创建返回对象
        CompletableFuture<Void> d = new CompletableFuture<Void>();
         // 线程池执行
        e.execute(new AsyncRun(d, f));
        //返回future
        return d;
    }

   static final class AsyncRun extends ForkJoinTask<Void>
            implements Runnable, AsynchronousCompletionTask {
        CompletableFuture<Void> dep; Runnable fn;
        AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
            this.dep = dep; this.fn = fn;
        }

        public final Void getRawResult() { return null; }
        public final void setRawResult(Void v) {}
        public final boolean exec() { run(); return true; }

        public void run() {
            CompletableFuture<Void> d; Runnable f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                // 任务没有完成
                if (d.result == null) {
                    try {
                   // 运行
                        f.run();
                    //设置返回结果null
                        d.completeNull();
                    } catch (Throwable ex) {
                        d.completeThrowable(ex);
                    }
                }
                 //弹出依赖当前结果的节点,执行
                d.postComplete();
            }
        }
    }

CompletableFuture<U> supplyAsync(Supplier<U> supplier):有返回结果

    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
                                                     Supplier<U> f) {
        if (f == null) throw new NullPointerException();
         // 创建future对象
        CompletableFuture<U> d = new CompletableFuture<U>();
         // 线程池执行AsyncSupply对象(包装f)
        e.execute(new AsyncSupply<U>(d, f));
        // 返回future
            return d;
        }

         public void run() {
            CompletableFuture<T> d; Supplier<T> f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                if (d.result == null) {
                    try {
                        // f.get获取值
                        d.completeValue(f.get());
                    } catch (Throwable ex) {
                        d.completeThrowable(ex);
                    }
                }
                // 通知依赖节点
                d.postComplete();
            }
  • 介绍l主要的运行任务方法;

int  getNumberOfDependents:获取依赖该节点的任务数

 // 获取依赖该节点的任务数 
public int getNumberOfDependents() {
        int count = 0;
        // 遍历一遍
        for (Completion p = stack; p != null; p = p.next)
            ++count;
        return count;
    }
  • 基本的方法实现已经结束;

4.总结

  • CompletableFuture对异步编程的支持很强,可以根据我们的业务进行灵活的运用;在框架中异步思想的运行很多,因此对CompletableFuture的运用要非常熟悉,后续我们对CompletableFuture的所有方法细节实现进行导读,如何通知其他依赖节点,then系列方法执行后,是如何保存节点信息,异常情况,其他信息如何处理等;
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值