Java8 CompletableFuture与ThreadPoolTaskExecutor实践

一、CompletableFuture介绍

Jdk8 CompletableFuture提供了新的异步编程思路,可以对多个异步处理进行编排,实现更复杂的异步处理。其内部使用ForkJoinPool实现异步,使用CompletableFuture可以把回调的实现改为同步调用实现。CompletableFuture提供了50多个API,现在分为场景来做介绍:

1.1 3个服务并发调用,然后对结果进行合并处理,阻塞主线程。

Java8 CompletableFuture与ThreadPoolTaskExecutor实践_第1张图片

	CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f1");
            return "f1";
        });
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f2");
            return "f2";
        });
        CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f3");
            return "f3";
        });

        CompletableFuture.allOf(f1, f2, f3).thenApply((Integer) -> {
            try {
                System.out.println(Thread.currentThread() + f1.get());
                System.out.println(Thread.currentThread() + f2.get());
                System.out.println(Thread.currentThread() + f3.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
            return 1;
        });
        System.out.println(Thread.currentThread() + " end");

执行结果:
hread[ForkJoinPool.commonPool-worker-1,5,main]-f1
Thread[ForkJoinPool.commonPool-worker-1,5,main]-f2
Thread[ForkJoinPool.commonPool-worker-2,5,main]-f3
Thread[main,5,main]f1
Thread[main,5,main]f2
Thread[main,5,main]f3
Thread[main,5,main] end

对于这种场景,实际上也可以使用CountDownLatch来解决。

1.2 3个服务并发调用,然后对结果进行合并处理,不阻塞主线程。

Java8 CompletableFuture与ThreadPoolTaskExecutor实践_第2张图片

	CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f1");
            return "f1";
        });
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f2");
            return "f2";
        });
        CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f3");
            return "f3";
        });

        CompletableFuture.allOf(f1, f2, f3).thenApplyAsync((Integer) -> {
            try {
                System.out.println(Thread.currentThread() + f1.get());
                System.out.println(Thread.currentThread() + f2.get());
                System.out.println(Thread.currentThread() + f3.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
            return 1;
        });
        System.out.println(Thread.currentThread() + " end");

执行结果:
Thread[ForkJoinPool.commonPool-worker-1,5,main]-f1
Thread[ForkJoinPool.commonPool-worker-1,5,main]-f2
Thread[ForkJoinPool.commonPool-worker-2,5,main]-f3
Thread[main,5,main] end
Thread[ForkJoinPool.commonPool-worker-2,5,main]f1
Thread[ForkJoinPool.commonPool-worker-2,5,main]f2
Thread[ForkJoinPool.commonPool-worker-2,5,main]f3

1.3 s1执行完成后并发执行s2和s3,然后消费相关结果,不阻塞主线程。

Java8 CompletableFuture与ThreadPoolTaskExecutor实践_第3张图片

	CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f1");
            return "f1";
        });
        CompletableFuture<String> f2 = f1.thenApplyAsync((v) -> {
            System.out.println(Thread.currentThread() + "-f2");
            return "f2";
        });
        CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread() + "-f3");
            return "f3";
        });

        f2.thenCombineAsync(f3, (f2s, f3s) -> {
            System.out.println(Thread.currentThread() + f2s);
            System.out.println(Thread.currentThread() + f3s);
            return null;
        });

        System.out.println(Thread.currentThread() + " end");

二、ThreadPoolTaskExecutor介绍

ThreadPoolTaskExecutor是一个spring的线程池技术,它是使用jdk中的java.util.concurrent.ThreadPoolExecutor进行实现。

delegate = new org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor();
// 核心数
delegate.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 线程池数
delegate.setMaxPoolSize(Runtime.getRuntime().availableProcessors() + 10);
// 队列数
delegate.setQueueCapacity(1000);
// 等待实际
delegate.setKeepAliveSeconds(300);
// 拒绝策略
delegate.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
// 
delegate.setTaskDecorator(new ContextCopyingDecorator());
delegate.initialize();
// taskDecorator主要是对Runnable任务装饰一下, 在任务执行时完成异常日志打印、ThreadLocal清理等功能
static class ContextCopyingDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            User user = AppContext.getCurrentUser();
            return () -> {
                try {
                    AppContext.clearThreadContext();
                    AppContext.putThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY, user);
                    runnable.run();
                } finally {
                    AppContext.clearThreadContext();
                }
            };
        }
    }

依托TaskDecorator可以实现线程信息信息共享:比如当前用户信息,时区信息,完成异常日志打印、ThreadLocal清理等功能,所以在使用CompletableFuture的时候结合TaskDecorator可以让使用者无感知的切换为异步或者同步方式。

三、参考链接

  1. Java8新的异步编程方式 CompletableFuture 组合式 异步编程
  2. spring ThreadPoolTaskExecutor使用总结

你可能感兴趣的:(Java并发)