当前位置: 首页 > news >正文

CompletableFuture异步执行用法详解

CompletableFuture异步执行用法详解

  • 常用API
    • thenAccept()
    • thenRun()
    • thenApply()
    • thenCombine()
    • thenAcceptBoth()
    • runAfterBoth()
    • applyToEither()
    • acceptEither()
    • runAfterEither()
    • exceptionally()
    • whenComplete()
    • handle()
  • CompletableFuture实现简单业务
  • 整体Demo(以上代码的合并版)

常用API

thenAccept()

thenAccept()用法:
1. 此方法【没有返回值】
2. 此方法需要借助【某一个】异步代码逻辑执行
3. 此方法【可以拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenAccept()
5. 此方法不会造成阻塞
private static void thenAcceptTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture
        	.supplyAsync(() -> "task A");
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task B";
        });
        // 放开此睡眠,thenAccept()中逻辑会正常执行
        // Thread.sleep(5000);
        futureB.thenAccept(b -> {
            System.out.println("run task C.");
            System.out.println("param:" + b);
        });
    }

thenRun()

thenRun()用法:
1. 此方法【没有返回值】
2. 此方法需要借助【某一个】异步代码逻辑执行
3. 此方法【不能拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenRun()
5. 此方法不会造成阻塞
    private static void thenRunTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture
        	.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task A";
        });
        // 放开此睡眠,thenRun()中逻辑会正常执行
        // Thread.sleep(5000);
        futureA.thenRun(() -> System.out.println("running task B"));
    }

thenApply()

thenApply()用法:
1. 此方法【有返回值】
2. 此方法需要借助【某一个】异步代码逻辑执行
3. 此方法【能拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenApply()
5. 此方法会造成阻塞
    private static void thenApplyTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture
        	.supplyAsync(() -> {
            a = a + 1;
            System.out.println(a + "1");
            return "task a ";
        });
        CompletableFuture<String> futureB = futureA.thenApply(s -> {
            // 下面睡眠解注释,会阻塞后续执行
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            a = a + 1;
            System.out.println(a + "2");
            return s + "and task b ";
        });
        CompletableFuture<String> future3 = futureB.thenApply(s -> {
            a = a + 1;
            System.out.println(a + "3");
            return s.toUpperCase();
        });
        System.out.println("4");
        System.out.println("a=" + a);
        // 输出最后异步任务返回值,会阻塞后续代码块
        // System.out.println(future3.join());
    }

thenCombine()

thenCombine()用法,用于处理两个阶段的结果:
1. 此方法【有返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【能拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenCombine()
5. 此方法会造成后续代码阻塞
    private static void thenCombineTest() {
        CompletableFuture<String> taskA = CompletableFuture
        	.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        CompletableFuture<String> taskC = taskA.thenCombine(taskB, (a, b) -> {
            System.out.println("c:" + LocalDateTime.now());
            return (a + b).toUpperCase();
        });
        System.out.println(LocalDateTime.now());
        // System.out.println("数据合并:" + taskC.join());
    }

thenAcceptBoth()

thenAcceptBoth()用法,用于处理两个阶段的结果:
1. 此方法【无返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【能拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenAcceptBoth()
5. 此方法【不会造成阻塞】
    private static void thenAcceptBothTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());

            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.thenAcceptBoth(taskB, (a, b) -> {
            System.out.println("c:" + LocalDateTime.now());
            System.out.println((a + b).toUpperCase());
        });
        System.out.println(LocalDateTime.now());
    }

runAfterBoth()

runAfterBoth()用法,用于处理两个阶段的结果:
1. 此方法【无返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【不能拿到】被依赖的异步逻辑的返回值
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行runAfterBoth()
5. 此方法【不会造成阻塞】
    private static void runAfterBothTest() {
        CompletableFuture<String> taskA = CompletableFuture
        	.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.runAfterBoth(taskB, () -> {
            System.out.println("c:" + LocalDateTime.now());
        });
        System.out.println(LocalDateTime.now());
    }

applyToEither()

applyToEither()用法,用于处理两个阶段的结果:
1. 此方法【有返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【能返回】被依赖的异步逻辑中【最先拿到的返回值】
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行applyToEither()
5. 此方法【不会造成阻塞】
    private static void applyToEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        CompletableFuture<String> taskC = taskA.applyToEither(taskB, info -> {
            System.out.println("c:" + LocalDateTime.now());
            return info;
        });
        System.out.println(LocalDateTime.now());
        // 此方法阻塞后续代码
        // System.out.println("数据输出:" + taskC.join());
    }

acceptEither()

acceptEither()用法,用于处理两个阶段的结果:
1. 此方法【没有返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【能返回】被依赖的异步逻辑中【最先拿到的返回值】
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行acceptEither()
5. 此方法【不会造成阻塞】
    private static void acceptEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.acceptEither(taskB, info -> {
            System.out.println("c:" + LocalDateTime.now());
            System.out.println(info);
        });
        System.out.println(LocalDateTime.now());
    }

runAfterEither()

runAfterEither()用法,用于处理两个阶段的结果:
1. 此方法【没有返回值】
2. 此方法需要借助【某两个】异步代码逻辑执行
3. 此方法【不能返回】被依赖的异步逻辑中【最先拿到的返回值】
4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行runAfterEither()
5. 此方法【不会造成阻塞】
    private static void runAfterEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.runAfterEither(taskB, () -> {
            System.out.println("c:" + LocalDateTime.now());
        });
        System.out.println(LocalDateTime.now());
    }

exceptionally()

exceptionally()用法,用于处理异步逻辑中的异常:
1. 此方法【有返回值】,即使异步逻辑没有返回值,也需要返回null
2. 此方法接收Exception异常对象,并处理异常信息
    private static void exceptionallyTest() {
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 0))
                .thenApply(s -> " resultA:" + s)
                .exceptionally(e -> {
                    System.out.println(e.getMessage());
                    return "futureA result: errorA";
                });
        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "runB:" + 50)
                .thenApply(s -> "resultB:" + s)
                .exceptionally(e -> "futureB result: errorB");
        System.out.println(futureA.join());// 报错进入exceptionally()处理
        System.out.println(futureB.join());// 未报错正常结束
    }

whenComplete()

whenComplete()用法,用于处理异步逻辑中的异常:
1. 此方法【没有返回值】
2. 此方法不管异步逻辑中是否有异常,都会走这个方法
3. 此方法有两个接收值,一个接收【依赖异步逻辑的返回值】,一个接收【Exception异常】
4. 两种顺序:
     4-1. 执行顺序 supplyAsync() -> thenApply() -> whenComplete() -> exceptionally()
         4-1-1. whenComplete()和exceptionally()都会接收到异常信息
         4-1-2. 最终join()返回的值是exceptionally()的返回值
     4-2. 执行顺序 supplyAsync() -> thenApply() -> exceptionally() -> whenComplete()
         4-2-1. exceptionally()会接收到异常信息,并处理后返回
         4-2-2. whenComplete()接收值是exceptionally()的返回值,接收的异常为null
         4-2-3. 最终join()返回的值是exceptionally()的返回值
    private static void whenCompleteTest() {
        // 顺序一
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 1))
                .thenApply(s -> " resultA:" + (100 / 0) )
                .whenComplete((s, e) -> {
                    if (s != null) {
                        System.out.println("whenComplete:" + s);//未执行
                    }
                    if (e == null) {
                        System.out.println("whenComplete:" + s);//未执行
                    } else {
                    	//java.lang.ArithmeticException: / by zero
                        System.out.println("whenComplete:" + e.getMessage());
                    }
                })
                .exceptionally(e -> {
                	//ex:java.lang.ArithmeticException: / by zero
                    System.out.println("exceptionally():" + e.getMessage()); 
                    return "exceptionally() result";
                });
        // 顺序二
        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 1))
                .thenApply(s -> " resultA:" + (100 / 0) )
                .exceptionally(e -> {
                	//ex:java.lang.ArithmeticException: / by zero
                    System.out.println("exceptionally():" + e.getMessage()); 
                    return "exceptionally() result";
                })
                .whenComplete((s, e) -> {
                    if (e == null) {
                    	//whenComplete:exceptionally() result
                        System.out.println("whenComplete:" + s);
                    } else {
                    	//未执行
                        System.out.println("whenComplete:" + e.getMessage());
                    }
                });
        //futureA.join():exceptionally() result
        System.out.println("futureA.join():" + futureA.join());
        //futureB.join():exceptionally() result
        System.out.println("futureB.join():" + futureB.join());
    }

handle()

handle()用法,用于处理异步逻辑中的异常:
1. 此方法【有返回值】
2. 此方法不管异步逻辑中是否有异常,都会走这个方法
3. 此方法有两个接收值,一个接收【依赖异步逻辑的返回值】,一个接收【Exception异常】
4. 两种顺序:
     4-1. 执行顺序 supplyAsync() -> thenApply() -> handle() -> exceptionally()
         4-1-1. handle()会接收到异常信息,并进行处理后返回
         4-1-2. 最终join()返回的值是handle()的返回值
         4-1-3. 如果handle()也有异常,会进入exceptionally(),并处理异常返回,
         		最终join()返回的值是exceptionally()的返回值
     4-2. 执行顺序 supplyAsync() -> thenApply() -> exceptionally() -> handle()
         4-2-1. exceptionally()会接收到异常信息,并处理后返回
         4-2-2. handle()接收值是exceptionally()的返回值,接收的异常为null
         4-2-3. 最终join()返回的值是handle()的返回值
    private static void handleTest() {
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "supplyAsync() result:" + (100 / 0))
                .thenApply(s -> "thenApply() result:" + s)
                .handle((s, e) -> {
                    if (e == null) {
                        System.out.println(s);//未执行
                    } else {
                    	//java.lang.ArithmeticException: / by zero
                        System.out.println(e.getMessage());
                    }
                    return "handle() result:" + (s == null ? "1000" : s);
                })
                .exceptionally(e -> {
                    System.out.println("ex:" + e.getMessage()); //未执行
                    return "futureA result exceptionally()";
                });
        System.out.println(futureA.join());//handle() result:1000

        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "supplyAsync() result:" + (100 / 0))
                .thenApply(s -> "thenApply() result:" + s)
                .exceptionally(e -> {
                	// java.lang.ArithmeticException: / by zero
                    System.out.println("ex:" + e.getMessage()); 
                    return "futureB result exceptionally()";
                })
                .handle((s, e) -> {
                    if (e == null) {
                        System.out.println(s);// futureB result exceptionally()
                    } else {
                        System.out.println(e.getMessage());// 未执行
                    }
                    return "handle() result:" + (s == null ? "1000" : s);
                });
        //handle() result:futureB result exceptionally()
        System.out.println(futureB.join());
    }

CompletableFuture实现简单业务

场景:异步执行逻辑,并每1秒循环获取返回值,直到异步执行结束返回结果

  1. join()方法和get()方法:会一直阻塞后续的代码执行
  2. 如果【join()方法和get()】在timer执行之前,会阻塞循环定时器的执行
  3. 在【join()方法和get()方法】以后的代码都会被阻塞
  4. get(long timeout, TimeUnit unit)方法:经过指定时间直接返回值,会阻塞后续代码一段时间
    但是要注意这个方法调用的位置,可以尝试将此方法放到循环定时器之前调用,会与现在结果大不一样
    private static void businessExample() throws ExecutionException,
    	 InterruptedException, TimeoutException {
        // 异步执行逻辑
        CompletableFuture<String> stringCompletableFuture1 = CompletableFuture
        	.supplyAsync(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 制造异常
            int a = 1 / 0;
            return "stringCompletableFuture1";
        }).exceptionally(e -> {
            // 如果逻辑执行有异常,进入此方法处理异常
            throw new RuntimeException();
        });

        // 循环定时获取结果,获取成功后关闭任务
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 如果异步任务执行结束
                if (stringCompletableFuture1.isDone()) {
                    // 关闭并清理任务
                    timer.cancel();
                    System.out.println("done = true,stop task total = " 
                    	+ timer.purge());
                    // 输出最终结果
                    System.out.println("getNow():" 
                    	+ LocalDateTime.now() + "   " 
                    	+ + stringCompletableFuture1.getNow(" END"));
                } else {
                    System.out.println("getNow():" 
                    	+ LocalDateTime.now() + "   " 
                    	+ stringCompletableFuture1.getNow(" RUNNING"));
                }
            }
        }, 0, 1000);
        System.out.println("get(time):" 
        	+ stringCompletableFuture1.get(1000L, TimeUnit.MILLISECONDS));

        // 代码块
        {
            System.out.println("join():" + stringCompletableFuture1.join());
            System.out.println("get():" + stringCompletableFuture1.get());
        }


        System.out.println(Thread.currentThread().getName() + "running");
    }

整体Demo(以上代码的合并版)

import com.sun.deploy.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class TestCompletableFuture {
    public static int a = 0;

    public static void main(String[] args) throws InterruptedException {
        // API实践
//        thenAcceptTest();
//        thenRunTest();
//        thenApplyTest();
//        thenCombineTest();
//        thenAcceptBothTest();
//        runAfterBothTest();
//        applyToEitherTest();
//        acceptEitherTest();
//        runAfterEitherTest();
//        exceptionallyTest();
//        whenCompleteTest();
//        handleTest();
        // 业务实例
//        businessExample();
    }


    /**
     * handle()用法,用于处理异步逻辑中的异常
     * 1. 此方法【有返回值】
     * 2. 此方法不管异步逻辑中是否有异常,都会走这个方法
     * 3. 此方法有两个接收值,一个接收【依赖异步逻辑的返回值】,一个接收【Exception异常】
     * 4. 两种顺序:
     *      4-1. 执行顺序 supplyAsync() -> thenApply() -> handle() -> exceptionally()
     *          4-1-1. handle()会接收到异常信息,并进行处理后返回
     *          4-1-2. 最终join()返回的值是handle()的返回值
     *          4-1-3. 如果handle()也有异常,会进入exceptionally(),并处理异常返回,最终join()返回的值是exceptionally()的返回值
     *      4-2. 执行顺序 supplyAsync() -> thenApply() -> exceptionally() -> handle()
     *          4-2-1. exceptionally()会接收到异常信息,并处理后返回
     *          4-2-2. handle()接收值是exceptionally()的返回值,接收的异常为null
     *          4-2-3. 最终join()返回的值是handle()的返回值
     */
    private static void handleTest() {
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "supplyAsync() result:" + (100 / 0))
                .thenApply(s -> "thenApply() result:" + s)
                .handle((s, e) -> {
                    if (e == null) {
                        System.out.println(s);//未执行
                    } else {
                        System.out.println(e.getMessage());//java.lang.ArithmeticException: / by zero
                    }
                    return "handle() result:" + (s == null ? "1000" : s);
                })
                .exceptionally(e -> {
                    System.out.println("ex:" + e.getMessage()); //未执行
                    return "futureA result exceptionally()";
                });
        System.out.println(futureA.join());//handle() result:1000

        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "supplyAsync() result:" + (100 / 0))
                .thenApply(s -> "thenApply() result:" + s)
                .exceptionally(e -> {
                    System.out.println("ex:" + e.getMessage()); // java.lang.ArithmeticException: / by zero
                    return "futureB result exceptionally()";
                })
                .handle((s, e) -> {
                    if (e == null) {
                        System.out.println(s);// futureB result exceptionally()
                    } else {
                        System.out.println(e.getMessage());// 未执行
                    }
                    return "handle() result:" + (s == null ? "1000" : s);
                });
        System.out.println(futureB.join());//handle() result:futureB result exceptionally()
    }

    /**
     * whenComplete()用法,用于处理异步逻辑中的异常
     * 1. 此方法【没有返回值】
     * 2. 此方法不管异步逻辑中是否有异常,都会走这个方法
     * 3. 此方法有两个接收值,一个接收【依赖异步逻辑的返回值】,一个接收【Exception异常】
     * 4. 两种顺序:
     *      4-1. 执行顺序 supplyAsync() -> thenApply() -> whenComplete() -> exceptionally()
     *          4-1-1. whenComplete()和exceptionally()都会接收到异常信息
     *          4-1-2. 最终join()返回的值是exceptionally()的返回值
     *      4-2. 执行顺序 supplyAsync() -> thenApply() -> exceptionally() -> whenComplete()
     *          4-2-1. exceptionally()会接收到异常信息,并处理后返回
     *          4-2-2. whenComplete()接收值是exceptionally()的返回值,接收的异常为null
     *          4-2-3. 最终join()返回的值是exceptionally()的返回值
     */
    private static void whenCompleteTest() {
        // 顺序一
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 1))
                .thenApply(s -> " resultA:" + (100 / 0) )
                .whenComplete((s, e) -> {
                    if (s != null) {
                        System.out.println("whenComplete:" + s);//未执行
                    }
                    if (e == null) {
                        System.out.println("whenComplete:" + s);//未执行
                    } else {
                        System.out.println("whenComplete:" + e.getMessage());//java.lang.ArithmeticException: / by zero
                    }
                })
                .exceptionally(e -> {
                    System.out.println("exceptionally():" + e.getMessage()); //ex:java.lang.ArithmeticException: / by zero
                    return "exceptionally() result";
                });
        // 顺序二
        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 1))
                .thenApply(s -> " resultA:" + (100 / 0) )
                .exceptionally(e -> {
                    System.out.println("exceptionally():" + e.getMessage()); //ex:java.lang.ArithmeticException: / by zero
                    return "exceptionally() result";
                })
                .whenComplete((s, e) -> {
                    if (e == null) {
                        System.out.println("whenComplete:" + s);//whenComplete:exceptionally() result
                    } else {
                        System.out.println("whenComplete:" + e.getMessage());//未执行
                    }
                });
        System.out.println("futureA.join():" + futureA.join());//futureA.join():exceptionally() result
        System.out.println("futureB.join():" + futureB.join());//futureB.join():exceptionally() result
    }

    /**
     * exceptionally()用法,用于处理异步逻辑中的异常
     * 1. 此方法【有返回值】,即使异步逻辑没有返回值,也需要返回null
     * 2. 此方法接收Exception异常对象,并处理异常信息
     */
    private static void exceptionallyTest() {
        CompletableFuture<String> futureA = CompletableFuture.
                supplyAsync(() -> "runA:" + (100 / 0))
                .thenApply(s -> " resultA:" + s)
                .exceptionally(e -> {
                    System.out.println(e.getMessage());
                    return "futureA result: errorA";
                });
        CompletableFuture<String> futureB = CompletableFuture.
                supplyAsync(() -> "runB:" + 50)
                .thenApply(s -> "resultB:" + s)
                .exceptionally(e -> "futureB result: errorB");
        System.out.println(futureA.join());// 报错进入exceptionally()处理
        System.out.println(futureB.join());// 未报错正常结束
    }

    /**
     * runAfterEither()用法,用于处理两个阶段的结果
     * 1. 此方法【没有返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【不能返回】被依赖的异步逻辑中【最先拿到的返回值】
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行runAfterEither()
     * 5. 此方法【不会造成阻塞】
     */
    private static void runAfterEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.runAfterEither(taskB, () -> {
            System.out.println("c:" + LocalDateTime.now());
        });
        System.out.println(LocalDateTime.now());
    }

    /**
     * acceptEither()用法,用于处理两个阶段的结果
     * 1. 此方法【没有返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【能返回】被依赖的异步逻辑中【最先拿到的返回值】
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行acceptEither()
     * 5. 此方法【不会造成阻塞】
     */
    private static void acceptEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.acceptEither(taskB, info -> {
            System.out.println("c:" + LocalDateTime.now());
            System.out.println(info);
        });
        System.out.println(LocalDateTime.now());
    }

    /**
     * applyToEither()用法,用于处理两个阶段的结果
     * 1. 此方法【有返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【能返回】被依赖的异步逻辑中【最先拿到的返回值】
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行applyToEither()
     * 5. 此方法【不会造成阻塞】
     */
    private static void applyToEitherTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        CompletableFuture<String> taskC = taskA.applyToEither(taskB, info -> {
            System.out.println("c:" + LocalDateTime.now());
            return info;
        });
        System.out.println(LocalDateTime.now());
        // 此方法阻塞后续代码
//        System.out.println("数据输出:" + taskC.join());
    }

    /**
     * runAfterBoth()用法,用于处理两个阶段的结果
     * 1. 此方法【无返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【不能拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行runAfterBoth()
     * 5. 此方法【不会造成阻塞】
     */
    private static void runAfterBothTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.runAfterBoth(taskB, () -> {
            System.out.println("c:" + LocalDateTime.now());
        });
        System.out.println(LocalDateTime.now());
    }

    /**
     * thenAcceptBoth()用法,用于处理两个阶段的结果
     * 1. 此方法【无返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【能拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenAcceptBoth()
     * 5. 此方法【不会造成阻塞】
     */
    private static void thenAcceptBothTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());

            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        taskA.thenAcceptBoth(taskB, (a, b) -> {
            System.out.println("c:" + LocalDateTime.now());
            System.out.println((a + b).toUpperCase());
        });
        System.out.println(LocalDateTime.now());
    }

    /**
     * thenCombine()用法,用于处理两个阶段的结果
     * 1. 此方法【有返回值】
     * 2. 此方法需要借助【某两个】异步代码逻辑执行
     * 3. 此方法【能拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenCombine()
     * 5. 此方法会造成后续代码阻塞
     */
    private static void thenCombineTest() {
        CompletableFuture<String> taskA = CompletableFuture.supplyAsync(() -> {
            System.out.println("a:" + LocalDateTime.now());
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task a ";
        });
        CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
            System.out.println("b:" + LocalDateTime.now());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task b ";
        });
        CompletableFuture<String> taskC = taskA.thenCombine(taskB, (a, b) -> {
            System.out.println("c:" + LocalDateTime.now());
            return (a + b).toUpperCase();
        });
        System.out.println(LocalDateTime.now());
//        System.out.println("数据合并:" + taskC.join());
    }

    /**
     * thenApply()用法
     * 1. 此方法【有返回值】
     * 2. 此方法需要借助【某一个】异步代码逻辑执行
     * 3. 此方法【能拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenApply()
     * 5. 此方法会造成阻塞
     */
    private static void thenApplyTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            a = a + 1;
            System.out.println(a + "1");
            return "task a ";
        });
        CompletableFuture<String> futureB = futureA.thenApply(s -> {
            // 下面睡眠解注释,会阻塞后续执行
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            a = a + 1;
            System.out.println(a + "2");
            return s + "and task b ";
        });
        CompletableFuture<String> future3 = futureB.thenApply(s -> {
            a = a + 1;
            System.out.println(a + "3");
            return s.toUpperCase();
        });
        System.out.println("4");
        System.out.println("a=" + a);
        // 输出最后异步任务返回值,会阻塞后续代码块
//        System.out.println(future3.join());
    }

    /**
     * thenRun()用法
     * 1. 此方法【没有返回值】
     * 2. 此方法需要借助【某一个】异步代码逻辑执行
     * 3. 此方法【不能拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenRun()
     * 5. 此方法不会造成阻塞
     */
    private static void thenRunTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task A";
        });
        // 放开此睡眠,thenRun()中逻辑会正常执行
//        Thread.sleep(5000);
        futureA.thenRun(() -> System.out.println("running task B"));
    }

    /**
     * thenAccept()用法
     * 1. 此方法【没有返回值】
     * 2. 此方法需要借助【某一个】异步代码逻辑执行
     * 3. 此方法【可以拿到】被依赖的异步逻辑的返回值
     * 4. 如果被依赖的异步逻辑没有执行完,不会等待,且不会执行thenAccept()
     * 5. 此方法不会造成阻塞
     */
    private static void thenAcceptTest() throws InterruptedException {
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> "task A");
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task B";
        });
        // 放开此睡眠,thenAccept()中逻辑会正常执行
//        Thread.sleep(5000);
        futureB.thenAccept(b -> {
            System.out.println("run task C.");
            System.out.println("param:" + b);
        });
    }

    /**
     * 场景:异步执行逻辑,并每1秒循环获取返回值,直到异步执行结束返回结果
     * 1. join()方法和get()方法:会一直阻塞后续的代码执行
     * 2. 如果【join()方法和get()】在timer执行之前,会阻塞循环定时器的执行,所以说在【join()方法和get()方法】以后的代码都会被阻塞
     * 3. get(long timeout, TimeUnit unit)方法:经过指定时间直接返回值,会阻塞后续代码一段时间,但是要注意这个方法调用的位置,可以尝试将此方法放到循环定时器之前调用,会与现在结果大不一样
     */
    private static void businessExample() throws ExecutionException, InterruptedException, TimeoutException {
        // 异步执行逻辑
        CompletableFuture<String> stringCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 制造异常
            int a = 1 / 0;
            return "stringCompletableFuture1";
        }).exceptionally(e -> {
            // 如果逻辑执行有异常,进入此方法处理异常
            throw new RuntimeException();
        });

        // 循环定时获取结果,获取成功后关闭任务
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // 如果异步任务执行结束
                if (stringCompletableFuture1.isDone()) {
                    // 关闭并清理任务
                    timer.cancel();
                    System.out.println("done = true,stop task total = " + timer.purge());
                    // 输出最终结果
                    System.out.println("getNow():" + LocalDateTime.now() + "   " + stringCompletableFuture1.getNow(" END"));
                } else {
                    System.out.println("getNow():" + LocalDateTime.now() + "   " + stringCompletableFuture1.getNow(" RUNNING"));
                }
            }
        }, 0, 1000);
        System.out.println("get(time):" + stringCompletableFuture1.get(1000L, TimeUnit.MILLISECONDS));

        // 代码块
        {
            System.out.println("join():" + stringCompletableFuture1.join());
            System.out.println("get():" + stringCompletableFuture1.get());
        }


        System.out.println(Thread.currentThread().getName() + "running");
    }
}

相关文章:

  • 画一个 “月饼” 陪我过中秋,使用 ESP32-C3 制作炫彩月饼(我为嵌入式工程师争取月饼)
  • 亚马逊审核 美国站安全带ASTMF1772安全绳攀岩绳EN892认证流程
  • AAA信用等级认证的流程和好处是什么
  • 现货黄金入门:初识心理
  • APS选型时需要考虑哪些因素?
  • Qt QProcess调用进程常用功能代码
  • 数据结构与算法-二分查找
  • 《大数据之路:阿里巴巴大数据实践》-第1篇 数据技术篇 -第2章 日志采集
  • 智慧食堂到底“智”在哪里?解决传统食堂5大问题
  • EFAK V3.0.1(原Kafka Eagle)安装部署
  • Spring Security 集成 OIDC 项目编码 | 认证(三)
  • 漏电继电器HLJ-400FS
  • HTB-Explore
  • DoozyUI⭐️十三 、UIToggle:开关讲解
  • windows部署nginx
  • 《深入 React 技术栈》
  • ➹使用webpack配置多页面应用(MPA)
  • 2017-09-12 前端日报
  • Android 架构优化~MVP 架构改造
  • Apache的80端口被占用以及访问时报错403
  • JAVA 学习IO流
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • mockjs让前端开发独立于后端
  • October CMS - 快速入门 9 Images And Galleries
  • PhantomJS 安装
  • SQLServer插入数据
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 解决iview多表头动态更改列元素发生的错误
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 通信类
  • 温故知新之javascript面向对象
  • 正则学习笔记
  • 正则与JS中的正则
  • ​TypeScript都不会用,也敢说会前端?
  • ​ubuntu下安装kvm虚拟机
  • ​VRRP 虚拟路由冗余协议(华为)
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # 达梦数据库知识点
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (02)vite环境变量配置
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)计算机毕业设计高校学生选课系统
  • (四)模仿学习-完成后台管理页面查询
  • (五)Python 垃圾回收机制
  • (转) Face-Resources
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)创业家杂志:UCWEB天使第一步
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .libPaths()设置包加载目录
  • .NET CLR Hosting 简介