CompletableFuture异步执行用法详解

常用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");
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值