CompletableFuture 线程编排

关键字记忆

when 任务完成时回调

both 两任务组合,都要完成

either 两任务组合,任一完成即可

run 无参无返回, apply 有参有返回, accept 有参无返回

async 异步

参考资料地址: 多线程之异步编排实例详解

创建线程的几种方式

import lombok.SneakyThrows;
import org.junit.Test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * 创建线程的几种方式
 *
 * @author lyn
 * @date 2024/04/02 14:20
 **/
public class CreateThreadMethodTest {
    @Test
    public void test1() {
        Thread01 thread01 = new Thread01();
        thread01.start();
    }

    @Test
    public void test2() {
        Runnable01 runnable01 = new Runnable01();
        Thread thread = new Thread(runnable01);
        thread.start();
    }

    @SneakyThrows
    @Test
    public void test3() {
        FutureTask<String> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
        System.out.println("阻塞等待线程执行完成,获取返回结果");
    }

    @SneakyThrows
    @Test
    public void test4() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("4 线程池的方式");
            }
        });
    }

    public class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("1 继承Thread类的方式");
        }
    }

    public class Runnable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("2 实现Runnable接口的方式");
        }
    }

    public class Callable01 implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println("3 实现callable 接口的方式");
            Thread.sleep(1000);
            return "res";
        }
    }
}

线程编排

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 线程编排
 * 参考资料链接: https://blog.csdn.net/weixin_53922163/article/details/128177316
 * @author lyn
 * @date 2024/04/08 10:42
 **/
@Slf4j
public class CompletableFutureTest {
    ExecutorService threadPool = Executors.newFixedThreadPool(5);

    @SneakyThrows
    @Test
    public void test() {
    }

    /**
     * 7 多任务组合
     */
    @SneakyThrows
    @Test
    public void test7() {
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            return "hello.jpg";
        }, threadPool);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性");
            return "白色+1TB";
        }, threadPool);

        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品介绍");
            return "Apple";
        }, threadPool);
        // 有一个任务执行完成 返回结果
        System.out.println(CompletableFuture.anyOf(futureImg, futureAttr, futureDesc).get());
        // 等待所有任务执行完成 返回结果
        CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        System.out.println("任务结果: " + futureImg.get() + " " + futureAttr.get() + " " + futureDesc.get());

    }

    /**
     * 6 两任务组合 - 一个完成
     */
    @SneakyThrows
    @Test
    public void test6() {
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1启动");
            return "任务1";
        }, threadPool);
        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {

            System.out.println("任务2启动");
            return "任务2";
        }, threadPool);
        supplyAsync1.runAfterEitherAsync(supplyAsync2, () -> {
            System.out.println("任务三启动");
        });
        supplyAsync1.acceptEither(supplyAsync2, res -> {
            System.out.println("任务三启动," + res);
        });

        System.out.println(supplyAsync1.applyToEitherAsync(supplyAsync2, (res) -> {
            System.out.println("任务三启动," + res);
            return res + "任务3";
        }).get());
    }

    /**
     * 5 两任务组合 - 都要完成
     */
    @SneakyThrows
    @Test
    public void test5() {
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1启动");
            return "任务1";
        }, threadPool);
        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {

            System.out.println("任务2启动");
            return "任务2";
        }, threadPool);
        //使用 runAfterBothAsync (无法获取之前任务执行的结果):
        supplyAsync1.runAfterBothAsync(supplyAsync2, () -> {
            System.out.println("任务3启动");
        }).get();
        //使用 thenAcceptBothAsync(可获取之前任务执行的结果,但不能返回)
        supplyAsync1.thenAcceptBothAsync(supplyAsync2, (p1, p2) -> {
            System.out.println("任务3启动," + p1 + "," + p2);

        }, threadPool).get();
        //使用 thenCombineAsync(可获取之前任务执行的结果,可修改并返回结果):
        String combineRes = supplyAsync1.thenCombineAsync(supplyAsync2, (p1, p2) -> {
            System.out.println("任务3启动," + p1 + "," + p2);
            return p1 + p2;
        }, threadPool).get();
        System.out.println(combineRes);

    }

    /**
     * 4 线程串行化方法
     */
    @SneakyThrows
    @Test
    public void test4() {
        //1 thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值
        CompletableFuture<Object> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = "welcome";
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).thenApplyAsync(res -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = res + " beijing";
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool);
        System.out.println(supplyAsync1.get());
        //2 thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
        CompletableFuture<Void> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = "welcome";
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).thenAcceptAsync(res -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = res + " beijing";
            System.out.println("运行结果:" + i);
        }, threadPool);
        System.out.println(supplyAsync2.get());
        //3 thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行 thenRun 的后续操作
        CompletableFuture<Void> supplyAsync3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = "welcome";
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).thenRunAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            String i = " beijing";
            System.out.println("运行结果:" + i);
        }, threadPool);
        System.out.println(supplyAsync3.get());

    }

    /**
     * 3 方法执行完成后的处理
     */
    @SneakyThrows
    @Test
    public void test3() {
        CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            return 1;
        }, threadPool).handle((res, ex) -> res + 1).whenComplete((res, ex) -> {
            System.out.println("异步任务完成,结果为: " + res + ",异常为:" + ex);
        });

    }

    /**
     * 2 计算完成时回调方法
     */
    @SneakyThrows
    @Test
    public void test2() {
        //1 whenComplete 是使用当前任务的线程继续执行任务。
        CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return 1;
        }, threadPool).whenComplete((res, ex) -> {
            System.out.println("计算完成后调用回调方法");

            System.out.println("当前线程" + Thread.currentThread().getName());
            System.out.println("异步任务完成,结果为: " + res + ",异常为:" + ex);
        });

        System.out.println("Main...Start...." + Thread.currentThread());
        // supplyAsync 可获取返回值
        //2 whenCompleteAsync是将任务继续提交给线程池来进行执行
        CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程" + Thread.currentThread());
            int i = 10 / 0;
            System.out.println("运行结果:" + i);
            return i;
        }, threadPool).whenCompleteAsync((res, exception) -> {
            // 当上面的任务执行完成,能得到结果和异常信息,但无法修改返回值
            System.out.println("异步任务完成,结果为:" + res + ",异常为:" + exception);
        }).exceptionally(throwable -> {
            // 可以感知异常,同时返回默认值
            return 101;
        });
        Integer integer = result.get();
        System.out.println("Main...End...." + integer);

    }

    /**
     * 1 创建异步对象
     */
    @SneakyThrows
    @Test
    public void test1() {
        //使用默认的线程池,无返回值
        CompletableFuture<Void> runAsync1 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "执行任务");
        });
        //使用自定义的线程池,无返回值
        CompletableFuture<Void> runAsync2 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "执行任务");
        }, threadPool);
        //使用默认的线程池,有返回值
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "执行任务");
            return "1";
        });
        System.out.println("supplyAsync1 结果:" + supplyAsync1.get(10, TimeUnit.MILLISECONDS));
        //使用自定义的线程池,有返回值
        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "执行任务");
            return "2";
        }, threadPool);
        System.out.println("supplyAsync2 结果:" + supplyAsync2.get(10, TimeUnit.MILLISECONDS));
    }
}
posted @ 2024-04-09 10:14  进击的小蔡鸟  阅读(53)  评论(0编辑  收藏  举报