代码编织梦想

前置知识

在开始本篇内容前我希望读者已经了解Java多线程的概念及其基本知识。

Completable常见方法

首先自定义一个线程池用于任务提交

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
        10,
        20,
        20,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<Runnable>(100),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.DiscardPolicy());

    // 文中用到的睡眠方法
    public static void sleep(int i) {
        try {
            TimeUnit.SECONDS.sleep(i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * submit(Callable<T> task): 将任务提交给线程池,返回值为Future对象
     */
    @Test
    public void test1() throws ExecutionException, InterruptedException {
        Future<String> submit = poolExecutor.submit(() -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
            return "hello threadPool~";
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println("threadPool result: " + submit.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

    /**
     * execute(Runnable command): 将任务提交给线程池,没有返回值
     */
    @Test
    public void test2() {
        poolExecutor.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
//            return "hello threadPool~"; 报错
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println("main endTime: " + System.currentTimeMillis());
        Sleeper.sleep(2);
    }

submit:

main startTime: 1664988253919
pool-1-thread-1 startTime: 1664988253919
pool-1-thread-1 endTime: 1664988254931
threadPool result: hello threadPool~
main endTime: 1664988254931


execute:

main startTime: 1664988269428
main endTime: 1664988269428
pool-1-thread-1 startTime: 1664988269428
pool-1-thread-1 endTime: 1664988270430

    /**
     * runAsync(Runnable runnable, Executor executor)
     * 类似于 Test2,线程池的 execute 方法
     * <p>
     * supplyAsync(Supplier<U> supplier, Executor executor)
     * 类似于 Test1,线程池的 submit 方法
     */
    @Test
    public void test3() throws ExecutionException, InterruptedException {
        CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
        }, poolExecutor);
        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println("main endTime: " + System.currentTimeMillis());
        Sleeper.sleep(2);

        System.out.println("===============supplyAsync==============");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
            return "hello supplyAsync~";
        }, poolExecutor);

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(future.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

main startTime: 1664988310101
main endTime: 1664988310101
pool-1-thread-1 startTime: 1664988310101
pool-1-thread-1 endTime: 1664988311111
===============supplyAsync==============
main startTime: 1664988312104
pool-1-thread-2 startTime: 1664988312104
pool-1-thread-2 endTime: 1664988313116
hello supplyAsync~
main endTime: 1664988313116 

    /**
     * thenApply(Function<? super T,? extends U> fn)
     * thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
     * 将第一个future对象的返回值传入第二个任务中,两者不同之处在于前者两个任务运行在一个线程,而后者不是。
     */
    @Test
    public void test4() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
            return "hello supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> future2 = future.thenApply((e) -> {
            System.out.println(Thread.currentThread().getName() + " startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " endTime: " + System.currentTimeMillis());
            return e + " hello!I am job2";
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(future2.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

pool-1-thread-1 startTime: 1664988334854
main startTime: 1664988334855
pool-1-thread-1 endTime: 1664988335863
pool-1-thread-1 startTime: 1664988335863
pool-1-thread-1 endTime: 1664988336866
hello supplyAsync~ hello!I am job2
main endTime: 1664988336866 

    /**
     * thenAccept(Consumer<? super T> action):
     * 接收一个参数,没有返回值
     * thenRun(Runnable action):
     * 不接收参数,没有返回值
     */
    @Test
    public void test5() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "hello supplyAsync~";
        }, poolExecutor);

        future.thenAccept((e) -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
        }).thenRun(() -> {
            System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        Sleeper.sleep(5);
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

pool-1-thread-1 job1 startTime: 1664988358769
main startTime: 1664988358770
pool-1-thread-1 job1 endTime: 1664988359776
pool-1-thread-1 job2 startTime: 1664988359776
pool-1-thread-1 job2 endTime: 1664988360785
pool-1-thread-1 job3 startTime: 1664988360785
pool-1-thread-1 job3 endTime: 1664988361800
main endTime: 1664988363772 

    /**
     * exceptionally(Function<Throwable, ? extends T> fn)
     * 若Job1有异常则执行Job2
     */
    @Test
    public void test6() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            try {
                throw new Exception("exception...");
            } catch (Exception e) {
                e.printStackTrace();
                return "exception...";
            }
        }, poolExecutor);

        CompletableFuture<String> exceptionally = future.exceptionally((exception) -> {
            System.out.println(Thread.currentThread().getName() + " exception startTime: " + System.currentTimeMillis());
            return exception.getMessage();
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(exceptionally.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

pool-1-thread-1 job1 startTime: 1664988463352
main startTime: 1664988463353
java.lang.Exception: exception...
    at com.shuttle.day03.completablefuture.CompletableFutureTest.lambda$test6$9(CompletableFutureTest.java:155)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
exception...
main endTime: 1664988464366 

    /**
     * whenComplete(BiConsumer<? super T, ? super Throwable> action)
     * 当 job1 完成时执行 job2 传入参数为 (job1返回值, job1抛出异常【若没有异常则为null】)
     */
    @Test
    public void test7() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
//            try {
//                throw new Exception("exception...");
//            } catch (Exception e) {
//                e.printStackTrace();
//                return "exception...";
//            }
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "hello supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> job2 = future.whenComplete((result, exception) -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            if (exception != null) {
                exception.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(job2.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

pool-1-thread-1 job1 startTime: 1664988554460
main startTime: 1664988554460
pool-1-thread-1 job1 endTime: 1664988555477
pool-1-thread-1 job2 startTime: 1664988555477
pool-1-thread-1 job2 endTime: 1664988556488
hello supplyAsync~
main endTime: 1664988556488 

    /**
     * handle(BiFunction<? super T, Throwable, ? extends U> fn)
     * 和whenComplete基本一致,但handle有返回值
     */
    @Test
    public void test8() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
//            try {
//                throw new Exception("exception...");
//            } catch (Exception e) {
//                e.printStackTrace();
//                return "exception...";
//            }
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "hello supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> job2 = future.handle((result, exception) -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            if (exception != null) {
                exception.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
            return result + "hello handle~";
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(job2.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
    }

pool-1-thread-1 job1 startTime: 1664988612783
main startTime: 1664988612783
pool-1-thread-1 job1 endTime: 1664988613786
pool-1-thread-1 job2 startTime: 1664988613786
pool-1-thread-1 job2 endTime: 1664988614793
hello supplyAsync~hello handle~
main endTime: 1664988614793 

    /**
     * thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)
     * thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)
     * runAfterBoth(CompletionStage<?> other, Runnable action)
     * <p>
     * job1.thenCombine(job2) 当job1和job2都完成时执行job3 可接收job1 和 job2 的返回值,并有新的返回值
     * thenAcceptBoth与thenCombine的区别就是没有返回值
     * runAfterBoth没有入参也没有返回值
     */
    @Test
    public void test9() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "helloA supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
            return "helloB supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> future3 = future.thenCombine(future2, (a, b) -> {
            System.out.println(Thread.currentThread().getName() + " thenCombine startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " thenCombine endTime: " + System.currentTimeMillis());
            return a + b;
        });

        future.thenAcceptBoth(future2, (a, b) -> {
            System.out.println(Thread.currentThread().getName() + " thenAcceptBoth startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " thenAcceptBoth endTime: " + System.currentTimeMillis());
        });

        future.runAfterBoth(future2, () -> {
            System.out.println(Thread.currentThread().getName() + " runAfterBoth startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " runAfterBoth endTime: " + System.currentTimeMillis());
        });

        System.out.println("main startTime: " + System.currentTimeMillis());
        System.out.println(future3.get());
        System.out.println("main endTime: " + System.currentTimeMillis());
        Sleeper.sleep(5);
    }

pool-1-thread-1 job1 startTime: 1664988653498
pool-1-thread-2 job2 startTime: 1664988653498
main startTime: 1664988653500
pool-1-thread-1 job1 endTime: 1664988654507
pool-1-thread-2 job2 endTime: 1664988654507
pool-1-thread-2 runAfterBoth startTime: 1664988654507
pool-1-thread-2 runAfterBoth endTime: 1664988655522
pool-1-thread-2 thenAcceptBoth startTime: 1664988655522
pool-1-thread-2 thenAcceptBoth endTime: 1664988656527
pool-1-thread-2 thenCombine startTime: 1664988656527
pool-1-thread-2 thenCombine endTime: 1664988657541
helloA supplyAsync~helloB supplyAsync~
main endTime: 1664988657544 

    /**
     * applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
     * acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
     * runAfterEither(CompletionStage<?> other, Runnable action)
     * <p>
     * job1.applyToEither(job2) 当job1 和 job2 之间有一个完成任务就执行job3【接受其中的返回值】
     * acceptEither与applyToEither的区别就是没有返回值
     * runAfterEither没有入参也没有返回值
     */
    @Test
    public void test10() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "helloA supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(2);
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
            return "helloB supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> stringCompletableFuture = future.applyToEither(future2, (a) -> {
            System.out.println(Thread.currentThread().getName() + " applyToEither startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " applyToEither endTime: " + System.currentTimeMillis());
            return a + " applyToEither";
        });

        future.acceptEither(future2, (a) -> {
            System.out.println(Thread.currentThread().getName() + " acceptEither startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " acceptEither endTime: " + System.currentTimeMillis());
        });

        future.runAfterEither(future2, () -> {
            System.out.println(Thread.currentThread().getName() + " runAfterEither startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " runAfterEither endTime: " + System.currentTimeMillis());
        });

        stringCompletableFuture.get();
        Sleeper.sleep(5);
    }

 pool-1-thread-1 job1 startTime: 1664988743472
pool-1-thread-2 job2 startTime: 1664988743472
pool-1-thread-1 job1 endTime: 1664988744487
pool-1-thread-1 runAfterEither startTime: 1664988744487
pool-1-thread-2 job2 endTime: 1664988745482
pool-1-thread-2 acceptEither startTime: 1664988745482
pool-1-thread-1 runAfterEither endTime: 1664988745497
pool-1-thread-1 applyToEither startTime: 1664988745497
pool-1-thread-2 acceptEither endTime: 1664988746487
pool-1-thread-1 applyToEither endTime: 1664988746503

    /**
     * thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)
     * 在job1执行完成后执行job2,如果job2的返回值不为 null,则返回一个新的Completable对象
     */
    @Test
    public void test11() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "helloA supplyAsync~";
        }, poolExecutor);

        CompletableFuture<String> stringCompletableFuture = future.thenCompose((e) -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
            return CompletableFuture.supplyAsync(() -> {
                System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
                Sleeper.sleep(1);
                System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
                return "hello thenCompose~";
            });
        });

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

 pool-1-thread-1 job1 startTime: 1664988778698
pool-1-thread-1 job1 endTime: 1664988779713
pool-1-thread-1 job2 startTime: 1664988779713
pool-1-thread-1 job2 endTime: 1664988780721
ForkJoinPool.commonPool-worker-9 job3 startTime: 1664988780722
ForkJoinPool.commonPool-worker-9 job3 endTime: 1664988781736
hello thenCompose~

    /**
     * allOf(CompletableFuture<?>... cfs): 所有任务执行完执行,没有返回值
     * anyOf(CompletableFuture<?>... cfs): 任一任务执行完执行,有返回值【任务最快的那个】
     */
    @Test
    public void test12() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job1 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            System.out.println(Thread.currentThread().getName() + " job1 endTime: " + System.currentTimeMillis());
            return "helloA supplyAsync~";
        }, poolExecutor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job2 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(2);
            System.out.println(Thread.currentThread().getName() + " job2 endTime: " + System.currentTimeMillis());
            return "helloB supplyAsync~";
        }, poolExecutor);
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " job3 startTime: " + System.currentTimeMillis());
            Sleeper.sleep(3);
            System.out.println(Thread.currentThread().getName() + " job3 endTime: " + System.currentTimeMillis());
            return "helloC supplyAsync~";
        }, poolExecutor);

        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(future1, future2, future3).whenComplete((result, exception) -> {
            System.out.println(Thread.currentThread().getName() + " allOf startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            if (exception != null) {
                exception.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " allOf endTime: " + System.currentTimeMillis());
        });

        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(future1, future2, future3).whenComplete((result, exception) -> {
            System.out.println(Thread.currentThread().getName() + " anyOf startTime: " + System.currentTimeMillis());
            Sleeper.sleep(1);
            if (exception != null) {
                exception.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " anyOf endTime: " + System.currentTimeMillis());
        });

        System.out.println("allOf " + completableFuture.get());
        System.out.println("anyOf " + objectCompletableFuture.get());
    }

 pool-1-thread-1 job1 startTime: 1664988904061
pool-1-thread-2 job2 startTime: 1664988904062
pool-1-thread-3 job3 startTime: 1664988904062
pool-1-thread-1 job1 endTime: 1664988905066
pool-1-thread-1 anyOf startTime: 1664988905066
pool-1-thread-2 job2 endTime: 1664988906065
pool-1-thread-1 anyOf endTime: 1664988906081
pool-1-thread-3 job3 endTime: 1664988907072
pool-1-thread-3 allOf startTime: 1664988907072
pool-1-thread-3 allOf endTime: 1664988908079
allOf null
anyOf helloA supplyAsync~

啊!常见方法终于列得差不多了,虽然看起来代码很多,但是其中有很多是重复度比较高的部分,能看到这并且都能手敲下来的都是勇士。

现在我们一起来看看下面这个模拟的真实场景需求:

目前某公司网站首页全部加载需要超过 3 秒的时间,其中包括静态图片模块、实时播报模块、三级分类搜索模块等等。现需要将其优化为 1 秒以内【假设其中所有模块单独运行都不超过 1 秒】,请给出解决方案。

原始伪代码 

    /* 模拟展示静态图片 */
    public void showPic() throws InterruptedException {
        Thread.sleep(500);
    }
    /* 模拟实时轮播图 */
    public void showLB() throws InterruptedException {
        Thread.sleep(800);
    }
    /* 模拟三级分类搜索 */
    public void threeSearch() throws InterruptedException {
        Thread.sleep(900);
    }
    /* 模拟其它资源加载 */
    public void other() throws InterruptedException {
        Thread.sleep(1000);
    }

    public static void main(String[] args) throws InterruptedException {
        CompletableFutureTest app = new CompletableFutureTest();
        long startTime = System.currentTimeMillis();
        // 展示静态图片
        app.showPic();
        // 实时轮播图
        app.showLB();
        // 三级分类搜索
        app.threeSearch();
        // 其它资源加载
        app.other();
        long endTime = System.currentTimeMillis();
        System.out.println("网页加载完毕! 总耗时: " + (endTime - startTime) + " ms");
    }

 网页加载完毕! 总耗时: 3219 ms


下面我们用CompletableFuture对其进行优化

        CompletableFutureTest app = new CompletableFutureTest();
        long startTime = System.currentTimeMillis();
        // 展示静态图片
        CompletableFuture<Void> job1 = CompletableFuture.runAsync(() -> {
            try {
                app.showPic();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("静态图片加载完毕~");
        });
        // 实时轮播图
        CompletableFuture<Void> job2 = CompletableFuture.runAsync(() -> {
            try {
                app.showLB();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("实时轮播图加载完毕~");
        });
        // 三级分类搜索
        CompletableFuture<Void> job3 = CompletableFuture.runAsync(() -> {
            try {
                app.threeSearch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("三级分类搜索加载完毕~");
        });
        // 其它资源加载
        CompletableFuture<Void> job4 = CompletableFuture.runAsync(() -> {
            try {
                app.other();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("其它资源加载完毕~");
        });
        // 组合所有任务
        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(job1, job2, job3, job4).whenComplete((result, exception) -> {
            if (exception != null) {
                // 模拟中间出现异常
                exception.printStackTrace();
            }
        });
        // 阻塞等待所有任务完成,时间取决于耗时最长的那个
        completableFuture.get();
        long endTime = System.currentTimeMillis();
        System.out.println("网页加载完毕! 总耗时: " + (endTime - startTime) + " ms");

静态图片加载完毕~
实时轮播图加载完毕~
三级分类搜索加载完毕~
其它资源加载完毕~
网页加载完毕! 总耗时: 1075 ms

上述仅仅只是模拟的一个非常简单的场景,模块之间没有相互依赖。CompletableFuture能做的事情可远远不止这些,例如一个模块需要依赖另一个模块的返回值,那么就可以使用thenApply【有返回值】或者thenAccept【无返回值】。

写在最后

CompletableFuture的出现为Java并发编程添加了新的思路,在此向 Doug Lea 大神致敬!不过在使用它的同时也要避免多线程带来的线程安全问题,希望大家有了足够的并发知识积累之后在实际工作中使用CompletableFuture,以免出现预期外的异常。



如果本篇内容对大家有帮助,希望多多支持哈~

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/shuttlepro/article/details/127178933

设计模式学习笔记 - 单例设计模式_金海湖底有宝藏的博客-爱代码爱编程

设计模式学习笔记 - 单例设计模式 一、设计模式简介二、单例设计模式1、单例模式简介2、实现方式2.1 饿汉式(静态常量)2.2 饿汉式(静态代码块)2.3 懒汉式(线程不安全)2.4 懒汉式(线程安全,同步方法)2

java项目本地部署宝塔搭建实战报修小程序springboot版系统源码_web测评的博客-爱代码爱编程

大家好啊,我是测评君,欢迎来到web测评。 有个朋友前两天发了一套java的源码给我,让我录制一个搭建视频,我抽空看了一下,本期就给大家带来这套Java开发的报修小程序springboot版系统源码。 技术架构

在 idea 中用 nacos2.1.0 源码启动集群模式并调试_魔道不误砍柴功的博客-爱代码爱编程

单机模式 1、源码 clone 下来之后 2、导入 IDEA 3、compile 编译(主要是让 proto 和 istio 能够自动生成 Java 类),如果没生成,切换个 Maven直接再来一次即可。 4、单机模

较多业步骤场景通用框架_interfacej的博客-爱代码爱编程

我们工作的大部分时间都在写业务代码,如何写好业务代码必然是我们追求的一大目标,在编程方面,简单、易懂、可扩展性是衡量代码质量的通用标准,所以在工作中,我们能用java将产品经理的想法表达出来还不够,我们产出的内容最好还能让其

java计算机毕业设计毕业生派遣系统mybatis+系统+数据库+调试部署_云清网络的博客-爱代码爱编程

JAVA计算机毕业设计毕业生派遣系统Mybatis+系统+数据库+调试部署 JAVA计算机毕业设计毕业生派遣系统Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件:idea eclipse 前端技术:Layui、HTML、CSS、JS、JQuery等技术 后端技术:JA

[servlet 5]部署servlet项目到云服务器_三金c_c的博客-爱代码爱编程

Java Servlet项目打包到云服务器的操作。 本次环境是Centos 7.6,使用的是腾讯云服务器。 目录 安装JDK环境安装Tomcat安装mysql打包War并部署 安装JDK环境 先使用命令,查

redis数据结构,一个字牛。_柒间的博客-爱代码爱编程

redis的数据结构 redis前导知识 redis是什么? The open source, in-memory data store used by millions of developers as a d

java-爱代码爱编程

标准输出流 Java通过系类System实现标准输入\输出的功能,定义了三个变量:in、out、err。这3个流在Java中都定义为静态变量,可以直接通过System类进行调用。 System.in : 表示标准输入,通

基于java演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署_ssh 演唱会门票预约管理系统-爱代码爱编程

基于JAVA演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署 基于JAVA演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件:idea eclipse 前端技术:Layui、HTML、CSS、JS、JQuery等技术 后端技术

apache doris 安装部署指南-爱代码爱编程

前言 本文隶属于专栏《大数据安装部署》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 准备 建议下载下面的 2 个安装包 Apache Doris 1.1.2 FE 安装包 Apa

java.基础-爱代码爱编程

1、Scanner输入 package com.company; import java.util.Scanner; public class ScannerTest { public static void main(String[] args) { Scanner scan=new Scanner((System.in)); Sys

(附源码)计算机毕业设计ssm宠物短期寄养平台_基于ssm宠物寄养中心系统-爱代码爱编程

项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM + mybatis + Maven + Vue 等等组成,B/S模式 + Maven管理等等。

jsp+servlet + tomcat实现用户登录(三)实现登出功能【javaweb、无数据库】_jsp servlet logout-爱代码爱编程

1.添加退出标签 在登录成功的页面下,添加以下代码 <form action="logout"> <input type="submit" value="退出登录" /> </for

nacos2.x服务注册心跳学习分享_nacos客户端上报心跳 鉴权吗-爱代码爱编程

nacos 2.1.0 前言 最近在学习nacos心跳机制的。我一开始从网上搜到了许多2.0之前的配置,结果并不起作用,并且默认心跳机制也与自己实际测试不同。在我看了nacos官网文档之后,我明白了nacos2

mybatis的使用_mybatis 用法-爱代码爱编程

在前面我们操作数据库的时候都是使用JDBC,我们发现它的操作太繁琐,为了解决这个问题,就提出了MyBatis。MyBatis就是更加简单的完成程序和数据库交互的工具,MyBatis是一个ORM框架(Object Relational Mapping),也就是对象映射。 在该框架中: 数据库表(table)被映射为类(class); 记录(record

【nacos】安装与部署_nacos安装配置和部署教程-爱代码爱编程

安装与部署 Nacos服务器是独立安装部署的,因此我们需要下载最新的Nacos服务端程序,下载地址:https://github.com/alibaba/nacos, 我们直接下载zip文件即可。 接着我们将文件进行解压,得到以下内容:  我们直接将其拖入到项目文件夹下,便于我们一会在IDEA内部启动,接着添加运行配置:  其中-m st

【java】封装_java封装-爱代码爱编程

路漫漫其修远兮 吾将上下而求索 目录 1.封装  1.1 封装的概念 1.2 访问限定符 1.3 封装扩展之包  2.static成员 2.1 static修饰的成员变量  2.2 static修饰的成员方法 2.3 static成员变量初始化  3.代码块 3.1代码块的概念以及代码块的分类 3.2 普通代码块  3.