并发编程:浅谈CompletionService 和 CompletableFuture (附高德笔试题)

一、CompletionService

1. 原理

  内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果按照完成的先后顺序排序。内部有一个先进先出的队列,用于保存已经执行完成的Future,通过调用它的take方法或者poll方法,可以获取到一个已经执行完成的Future,进而通过调用Future接口的实现类的get方法获取到最终结果。

2.应用场景

  Callable + Future 可以实现多个Task并行执行,但是遇到前面的task执行较慢时,需要阻塞等待前面的task执行完才能获取到后面task的执行结果。
  CompletionService的主要功能就是一边生成任务,一边获取任务的返回值。让两件事分开执行,任务之间不会互相阻塞,可以实现执行完的先获取结果,不在依赖任务顺序。

简单说一下就是:
1.当需要批量提交异步任务的时候建议你使用CompletionService。
2.CompletionService能够让异步任务的执行结果有序化。先执行完的先进入阻塞队列
3.线程池隔离。CompletionService支持自己创建线程池,这种隔离性能避免几个特别耗时的任务拖垮整个应用的风险。

3.使用案例

案例一:向不同电商平台询价,并保存

public class CompletionServiceDemo2 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();

        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //创建 CompletionService
        ExecutorCompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
        //异步向电商S1询价
        cs.submit(() -> getPriceByS1(2));
        //异步向电商S2询价
        cs.submit(() -> getPriceByS2(8));
        //异步向电商S3询价
        cs.submit(() -> getPriceByS3(4));

        //将结果异步保存到数据库
        for (int i = 0; i < 3; i++) {
            Future<Integer> future = cs.take();
            Integer result = future.get();
            System.out.println("任务【" + result + "】完成");
            executor.execute(() -> {
                try {
                    save(result);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                long end = System.currentTimeMillis();
                System.out.println("耗时:" + (end - start) / 1000 + " s");
                break;
            }
        }
    }

    private static Integer getPriceByS2(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }

    private static Integer getPriceByS1(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }

    private static Integer getPriceByS3(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }

    private static void save(Integer price) throws InterruptedException {
        TimeUnit.SECONDS.sleep(1);
        System.out.println("保存价格:" + price);
    }
}

执行结果:
任务【2】完成
保存价格:2
任务【4】完成
保存价格:4
任务【8】完成
保存价格:8
耗时:9 s

案例二:并行地调用多个服务,只要有一个成功就返回结果

public class CompletionServiceDemo3 {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        //创建completionService
        ExecutorCompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
        //用于保存Future对象
        List<Future<Integer>> futures = new ArrayList<>();
        //提交异步任务,并保存 future到 futures
        futures.add(cs.submit(() -> getPriceByS1(5)));
        futures.add(cs.submit(() -> getPriceByS2(3)));
        futures.add(cs.submit(() -> getPriceByS3(2)));

        Integer result = null;
        //获取最快返回的任务执行结果
        try {
            for (int i = 0; i < 3; i++) {
                Future<Integer> future = cs.take();
                //将有结果的任务从结果集删除
                futures.remove(future);
                result = future.get();
                if (result != null) {
                    break;
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            //取消剩下的所有任务
            for (Future<Integer> future : futures) {
                future.cancel(true);
            }
        }

        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                long end = System.currentTimeMillis();
                System.out.println("耗时:" + (end - start) / 1000 + " s");
                break;
            }
        }
        System.out.println("最终结果:" + result);
    }

    private static Integer getPriceByS2(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }

    private static Integer getPriceByS1(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }

    private static Integer getPriceByS3(int i) throws InterruptedException {
        TimeUnit.SECONDS.sleep(i);
        return i;
    }
}

执行结果:
耗时:2 s
最终结果:2

案例三:(高德笔试题)多个任务并行执行,有一个任务执行失败了,任务就结束。要求:最快

没有找到参考答案,这个是我自己想的,我觉得应该是对的。如有不对或者更好的答案欢迎在评论区指正、赐教

简单说明一下:
关键字是指假设失败的任务。其他任务正常执行,当一个任务异常失败或者逻辑失败,程序立即结束。

public class QuickFailure {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int random = new Random().nextInt(10);
        System.out.println("关键字:" + random);
        ExecutorService pools = Executors.newFixedThreadPool(5);
        ExecutorCompletionService<Integer> service = new ExecutorCompletionService<>(pools);
        List<Future<Integer>> futures = new ArrayList<>();
        //创建多个任务,并添加到集合
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            Future<Integer> future = service.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    System.out.println("任务 " + finalI + "开始...");
                    TimeUnit.SECONDS.sleep(finalI);
                    if (finalI == random) {
                        System.out.println("任务失败!!!");
                        return -1;
                    } else {
                        return finalI;
                    }
                }
            });
            futures.add(future);
        }

        //获取最快返回的任务结果
        for (int i = 0; i < 10; i++) {
            try {
                Future<Integer> future = service.take();
                //将有结果的任务从结果集中删除
                futures.remove(future);
                //查看结果是否失败
                Integer result = future.get();
                if (result == -1) {
                    //结果失败了,程序立即停止
                    System.out.println("任务【" + random + "】出现异常失败");
                    pools.shutdown();
                    break;
                } else {
                	//结果成功了,继续获取其他任务结果
                    System.out.println("任务【" + result + "】完成。");
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        //取消所有剩下的任务
        for (Future<Integer> future : futures) {
            future.cancel(true);
        }

        while (true) {
            if (pools.isTerminated()) {
                long end = System.currentTimeMillis();
                System.out.println("程序结束,耗时:" + (end - start) / 1000 + " s");
                break;
            }
        }
    }
}

执行结果:
关键字:5
任务 0开始…
任务 1开始…
任务 2开始…
任务 3开始…
任务 5开始…
任务 4开始…
任务【0】完成。
任务 6开始…
任务【1】完成。
任务 7开始…
任务【2】完成。
任务 8开始…
任务【3】完成。
任务 9开始…
任务【4】完成。
任务失败!!!
任务【5】出现异常失败
程序结束,耗时:5 s

以上结果发现,任务5是那个注定失败的任务。任务5之前的任务按时完成,当任务5执行失败了,即便已经提交的其他任务未执行,程序也按要求立即退出。

二、CompletableFuture

1.应用场景

a.依赖关系

  1. thenApply() 把前面异步任务的结果,交给后面的Function
  2. thenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回

b.聚合关系(and)

  1. thenCombine:任务合并,有返回值。
  2. thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。
  3. runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。

c.聚合关系(or)

  1. applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值。
  2. acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值。
  3. runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable)。

d.并行执行

  1. CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture并行执行。

2.详解

a.创建异步操作

public class CompletableFutureDemo1 {

    public static void main(String[] args) {
        Runnable runnable = () -> {
            System.out.println("执行无返回结果的任务");
        };
        CompletableFuture.runAsync(runnable);


        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行有返回值的异步任务");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello world";
        });

        String result = null;
        try {
            result = future.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(result);
    }
}

执行结果:
执行无返回结果的任务
执行有返回值的异步任务
hello world

b.结果处理

public class CompletableFutureDemo2 {

    static ExecutorService pool1 = Executors.newFixedThreadPool(3);

    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("thread name:" + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (new Random().nextInt(10) % 2 == 0) {
                int i = 12 / 0;
            }

            System.out.println("执行结束!");
            return "test";
        }, pool1);

        future.whenCompleteAsync(new BiConsumer<String, Throwable>() {
            @Override
            public void accept(String s, Throwable throwable) {
                System.out.println("thread name:" + Thread.currentThread().getName());
                System.out.println(s + " 执行完成!");
            }
        });

        future.exceptionally(new Function<Throwable, String>() {
            @Override
            public String apply(Throwable throwable) {
                System.out.println("执行失败:" + throwable.getMessage());
                return "异常xxx";
            }
        });

        new Scanner(System.in).nextLine();
    }
}

执行结果失败:
thread name:pool-1-thread-1
执行失败:java.lang.ArithmeticException: / by zero
thread name:ForkJoinPool.commonPool-worker-9
null 执行完成!
========================================================
执行结果成功:
thread name:pool-1-thread-1
执行结束!
thread name:ForkJoinPool.commonPool-worker-9
test 执行完成!

c.结果转换

public class CompletableFutureDemo4 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int result = new Random().nextInt(30);
                System.out.println("第一阶段:" + result);
                return result;
            }
        }).thenCompose(new Function<Integer, CompletionStage<Integer>>() {
            @Override
            public CompletionStage<Integer> apply(Integer param) {
                return CompletableFuture.supplyAsync(new Supplier<Integer>() {
                    @Override
                    public Integer get() {
                        int number = param * 2;
                        System.out.println("第二阶段:" + number);
                        return number;
                    }
                });
            }
        });

        System.out.println("最终结果:" + future.get());
    }
}

执行结果:
第一阶段:2
第二阶段:4
最终结果:4

d.结果消费

没有返回值,只对上一个结果处理

public class CompletableFutureDemo6 {

    public static void main(String[] args) {
        //thenAccept();
        //thenAcceptBoth();
        thenRun();
    }

    /**
     * 不关心结果,只对结果执行Action。
     * 与thenAccept不同的是,thenRun会在上一阶段 CompletionFuture 计算完成的时候执行一个Runnable,
     * Runnable 并不使用该CompletableFuture计算结果。
     */
    private static void thenRun() {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            int number = new Random().nextInt(10);
            System.out.println("第一阶段:" + number);
            return number;
        }).thenRun(() -> {
            System.out.println("thenRun 执行");
        });

        try {
            System.out.println("最终结果:" + future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 对两个结果进行消费
     */
    private static void thenAcceptBoth() {

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(3) + 1;
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(new Supplier<Object>() {
            @Override
            public Object get() {
                int number = new Random().nextInt(3) + 1;
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二阶段:" + number);
                return number;
            }
        });

        future1.thenAcceptBoth(future2, new BiConsumer<Integer, Object>() {
            @Override
            public void accept(Integer x, Object y) {
                System.out.println("最终结果:" + (x + (int) y));
            }
        }).join();
    }

    /**
     * 对单个结果进行消费
     */
    private static void thenAccept() {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            int number = new Random().nextInt(10);
            System.out.println("第一阶段:" + number);
            return number;
        }).thenAccept(number -> {
            try {
                Thread.sleep(5000);
                System.out.println("第二阶段:" + number * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        try {
            System.out.println("最终结果:" + future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

e.结果组合

public class CompletableFutureDemo7 {

    public static void main(String[] args) {

        thenCombine();
        //thenCombineAsync();
    }

    private static void thenCombineAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int number = new Random().nextInt(10);
                System.out.println("第一阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                System.out.println("第二阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> result = future1.thenCombineAsync(future2, new BiFunction<Integer, Integer, Integer>() {
            @Override
            public Integer apply(Integer x, Integer y) {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return x + y;
            }
        });

        try {
            System.out.println("最终结果:" + result.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("end...");

    }

    /**
     * 合并两个线程任务的结果,并进一步处理
     */
    private static void thenCombine() {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int number = new Random().nextInt(10);
                System.out.println("第一阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                System.out.println("第二阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> result = future1.thenCombineAsync(future2, new BiFunction<Integer, Integer, Integer>() {
            @Override
            public Integer apply(Integer x, Integer y) {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return x + y;
            }
        });

        try {
            System.out.println("最终结果:" + result.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("end...");
    }
}

f.任务交互

public class CompletableFutureDemo8 {

    public static void main(String[] args) {
        //applyToEither();
        //acceptEither();
        //runAfterEither();
        //runAfterBoth();
        //anyOf();
        allOf();
    }

    /**
     * 用来实现多个CompletableFuture的同时返回
     */
    private static void allOf() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("future1完成!");
                return "future1完成!";
            }
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("future2完成!");
                return "future2完成!";
            }
        });


        CompletableFuture<Void> combineFuture = CompletableFuture.allOf(future1, future2);
        try {
            combineFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("future1: " + future1.isDone() + ", future2: " + future2.isDone());

        try {
            System.out.println("future1 = " + future1.get() + "future2 = " + future2.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * anyOf方法的参数时多个给定的CompletableFuture,当其中的任何一个完成时,方法返回这个CompletableFuture
     */
    private static void anyOf() {
        Random random = new Random();
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(random.nextInt(5));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "hello";
            }
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    TimeUnit.SECONDS.sleep(random.nextInt(5));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return "world";
            }
        });

        CompletableFuture<Object> result = CompletableFuture.anyOf(future1, future2);
        try {
            System.out.println(result.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 两个线程任务相比较,两个全部执行完成,才进行下一步操作,不关心运行结果
     */
    private static void runAfterBoth() {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一阶段:1");
                return 1;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二阶段:2");
                return 2;
            }
        });

        future1.runAfterBoth(future2, new Runnable() {
            @Override
            public void run() {
                System.out.println("上面两个任务都执行完成了");
            }
        }).join();

    }

    /**
     * 两个线程任务比较,有任何一个执行完成,就进行下一步操作,不关心运行结果。
     */
    private static void runAfterEither() {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(5);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(5);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二阶段:" + number);
                return number;
            }
        });

        future1.runAfterEither(future2, new Runnable() {
            @Override
            public void run() {
                System.out.println("已经有一个任务完成了");
            }
        }).join();
    }

    /**
     * 两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的消费操作。无返回值
     */
    private static void acceptEither() {

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一阶段:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二阶段:" + number);
                return number;
            }
        });

        future1.acceptEither(future2, new Consumer<Integer>() {
            @Override
            public void accept(Integer number) {
                System.out.println("最快结果:" + number);
            }
        }).join();
    }

    /**
     * 两个线程任务相比较,先获得执行结果的,就对该结果进行下一步的转化操作。有返回值
     */
    private static void applyToEither() {

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                System.out.println("第一阶段start:" + number);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第一阶段end:" + number);
                return number;
            }
        });

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int number = new Random().nextInt(10);
                System.out.println("第二阶段start:" + number);
                try {
                    TimeUnit.SECONDS.sleep(number);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第二阶段end: " + number);
                return number;
            }
        });

        future1.applyToEither(future2, new Function<Integer, String>() {
            @Override
            public String apply(Integer number) {
                System.out.println("最快结果:" + number);
                return number * 2 + "";
            }
        }).join();
    }
}

3.使用案例

烧水泡茶

在这里插入图片描述
对于烧水泡茶这个程序,一种最优的分工方案:用两个线程 T1 和 T2 来完成烧水泡茶程序,
T1 负责洗水壶、烧开水、泡茶这三道工序,T2 负责洗茶壶、洗茶杯、拿茶叶三道工序,其中
T1 在执行泡茶这道工序时需要等待 T2 完成拿茶叶的工序。

  1. 基于Future实现
public class MakeTea {

	private static void doFuture() {
        FutureTask<String> ft2 = new FutureTask<>(new Task2());
        FutureTask<String> ft1 = new FutureTask<>(new Task1(ft2));

        //线程t1执行任务ft1
        Thread t1 = new Thread(ft1);
        t1.start();

        //线程t2执行任务ft2
        Thread t2 = new Thread(ft2);
        t2.start();

        //等待线程t1执行的结果
        try {
            System.out.println(ft1.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 需要执行:洗水壶 -> 烧开水 -> 泡茶(需要等待 task2送茶叶)
     */
    private static class Task1 implements Callable<String> {

        FutureTask<String> ft2;

        public Task1(FutureTask<String> ft2) {
            this.ft2 = ft2;
        }

        @Override
        public String call() throws Exception {
            System.out.println("t1: 洗水壶。。。");
            TimeUnit.SECONDS.sleep(1);

            System.out.println("t1: 烧开水。。。");
            TimeUnit.SECONDS.sleep(15);

            //获取t2线程送来的茶叶
            String tea = ft2.get();
            System.out.println("t1: 拿到茶叶【" + tea + "】");
            System.out.println("t1: 泡茶。。。");

            TimeUnit.SECONDS.sleep(3);
            return "上茶【" + tea + "】";
        }
    }

    /**
     * 需要执行:洗茶壶 -> 洗茶杯 -> 拿茶叶
     */
    private static class Task2 implements Callable<String> {

        @Override
        public String call() throws Exception {
            System.out.println("t2: 洗茶壶。。。");
            TimeUnit.SECONDS.sleep(1);

            System.out.println("t2: 洗茶杯。。。");
            TimeUnit.SECONDS.sleep(2);

            System.out.println("t2: 拿茶叶。。。");
            TimeUnit.SECONDS.sleep(1);
            return "龙井";
        }
    }
}

执行结果:
t1: 洗水壶。。。
t2: 洗茶壶。。。
t2: 洗茶杯。。。
t1: 烧开水。。。
t2: 拿茶叶。。。
t1: 拿到茶叶【龙井】
t1: 泡茶。。。
上茶【龙井】

  1. 基于CompletableFuture实现
public class MakeTea {
	
	private static void doCompletableFuture() {
        CompletableFuture<Void> ft1 = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("t1: 洗水壶。。。");
                    TimeUnit.SECONDS.sleep(1);

                    System.out.println("t1: 烧开水。。。");
                    TimeUnit.SECONDS.sleep(15);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        CompletableFuture<String> ft2 = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    System.out.println("t2: 洗茶壶。。。");
                    TimeUnit.SECONDS.sleep(1);

                    System.out.println("t2: 洗茶杯。。。");
                    TimeUnit.SECONDS.sleep(2);

                    System.out.println("t2: 拿茶叶。。。");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "龙井";
            }
        });

        //任务3: 任务1和任务2都完成以后执行:泡茶
        CompletableFuture<String> ft3 = ft1.thenCombine(ft2, new BiFunction<Void, String, String>() {
            @Override
            public String apply(Void unused, String tea) {
                System.out.println("t1: 拿到茶叶【" + tea + "】");
                System.out.println("t1: 泡茶。。。");

                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "上茶【" + tea + "】";
            }
        });

        //等待任务3的执行结果
        System.out.println(ft3.join());
    }
}

执行结果:
t1: 洗水壶。。。
t2: 洗茶壶。。。
t2: 洗茶杯。。。
t1: 烧开水。。。
t2: 拿茶叶。。。
t1: 拿到茶叶【龙井】
t1: 泡茶。。。
上茶【龙井】

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值