二、一篇学会CompletableFuture

目录

1、Future接口

2、FutureTask引出

3、FutureTask 到 CompletableFurue

3.1 FutureTask 优点

3.2 FutureTask缺点

4、CompletableFuture用法介绍

核心四个静态方法

减少阻塞和轮询whenCompleta

CompletableFuture常用API

1、获得结果和触发计算

2、对计算结果进行处理

3、对计算结果进行消费

4、CompleteFuture和线程池说明

5、对计算速度进行选用

6、对计算结果进行合并

7、CompletableFuture.anyOf 选择执行最快的

8、CompletableFuture.allOf 所有任务执行完毕


 1、Future接口

        Future接口定义了操作异步执行的方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务是否执行完毕等。

各个方法的含义

cancel(boolean)        尝试取消当前任务的执行。如果任务已经取消、已经完成或者其他原因不能取消,尝试将失败。如果任务还没有启动就调用了cancel(true),任务将永远不会被执行。如果任务已经启动,参数mayInterruptIfRunning将决定任务是否应该中断执行该任务的线程,以尝试中断该任务。
        如果任务不能被取消,通常是因为它已经正常完成,此时返回false,否则返回true
get()等待任务结束,然后获取结果,如果任务在等待过程中被终端将抛出InterruptedException,如果任务被取消将抛出CancellationException,如果任务中执行过程中发生异常将抛出ExecutionException。
get(long,TimeUnit)任务最多在给定时间内完成并返回结果,如果没有在给定时间内完成任务将抛出TimeoutException
isCancelled()如果任务在正常结束之前被被取消返回true
isDone()正常结束、异常或者被取消导致任务完成,将返回true

        Future是Java5中加的一个接口,它提供了一种异步并行计算的功能。如果主线程需要执行一个耗时的计算任务,我们就可以通过Future把这个任务放到异步线程中执行。主线程继续处理其他任务或先行结束,再通过Future获取计算结果。

2、FutureTask引出

在多线程中需要有三个条件需要被满足:多线程、有返回、异步任务

线程的申明有根本就是两种方式,一种继承Thread重写run方法,另一种就是实现Runnable接口实现run方法。多线程实现的方式与基础知识

1、线程接受自定义的参数几乎都需要Runnable这个参数

2、RunnableFuture<V> 接口实现了Runable接口和Future接口,同时满足了有返回,异步任务

 3、FuntureTask<V> 实现了RunnableFuture<V>接口,通过构造函数将Callable传入到FutureTask中

 代码实例

public class CallableThreadTest implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + " 执行");
        return Thread.currentThread().getName() + " 返回值";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThreadTest callableThread = new CallableThreadTest();
        FutureTask<String> futureTask = new FutureTask<>(callableThread);
        Thread t1 = new Thread(futureTask);
        t1.setName("线程1");
        t1.start();
        String s = futureTask.get();
        System.out.println(s);
    }
}

3、FutureTask 到 CompletableFurue

3.1 FutureTask 优点

        FutrueTask + 线程池可以提高多任务配合,可以显著提高执行效率

串行化执行:

 FutureTask + 线程池:

public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        long startTime = System.currentTimeMillis();
        FutureTask<String> task1 = new FutureTask<>(() -> {
            Thread.sleep(500);
           return "task1 返回结果";
        });
        executorService.submit(task1);
        FutureTask<String> task2 = new FutureTask<>(() -> {
            Thread.sleep(500);
            return "task2 返回结果";
        });
        executorService.submit(task2);
        FutureTask<String> task3 = new FutureTask<>(() -> {
            Thread.sleep(300);
            return "task3 返回结果";
        });
        executorService.submit(task3);
        // 等待所有任务执行完毕
        while (!(task1.isDone() && task2.isDone() && task3.isDone())){

        }
        long endTime = System.currentTimeMillis();
        System.out.println(task1.get());
        System.out.println(task2.get());
        System.out.println(task3.get());

        System.out.println("----执行了" + (endTime - startTime) + "毫秒");
        System.out.println(Thread.currentThread().getName() + "---------end");

        // 关闭线程池 最好放在finally中
        executorService.shutdown();
    }

3.2 FutureTask缺点

3.2.1 get()阻塞

public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> task1 = new FutureTask<>(() -> {
            Thread.sleep(5000);
           return "task1 返回结果";
        });
        Thread thread = new Thread(task1);
        thread.setName("自定义线程");
        thread.start();
        long startTime = System.currentTimeMillis();
        // 这里会阻塞 所以一般把get()方法放到最后
        System.out.println(task1.get());
        long endTime = System.currentTimeMillis();

        System.out.println("----get()阻塞了" + (endTime - startTime) + "毫秒");
        System.out.println(Thread.currentThread().getName() + "---------end");
    }

3.2.2 isDone()轮询

public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> futureTask = new FutureTask<String>(()->{
            System.out.println(Thread.currentThread().getName()+"\t ------副线程come in");
            try {
                TimeUnit.SECONDS.sleep(5);//暂停几秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task over";
        });
        Thread t1 = new Thread(futureTask,"t1");
        t1.start();

        System.out.println(Thread.currentThread().getName()+"\t-------主线程忙其他任务了");
        //1-------  System.out.println(futureTask.get(3,TimeUnit.SECONDS));//只愿意等3秒,过了3秒直接抛出异常

        //2-------更健壮的方式-------轮询方法---等副线程拿到才去get()
        //但是也会消耗cpu资源
        while(true){
            if(futureTask.isDone()){
                System.out.println(futureTask.get());
                break;
            }else{
                //暂停毫秒
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("正在处理中------------正在处理中");
            }
        }
    }

3.2.3 不可以多个线程任务前后依赖

4、CompletableFuture用法介绍

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

CompletionStage 实现多个任务前后依赖,一个任务完成后,可以继续下一个阶段。

核心四个静态方法

// 没有返回值,并且使用ForkJoinPool线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)

// 没有返回值,使用自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)

// 有返回值,并且使用ForkJoinPool线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) 

// 有返回值,使用自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)

使用方法:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        
        // 无返回参数,默认线程池
        System.out.println("--无返回参数,默认线程池 开始--");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long startTime = System.currentTimeMillis();
        System.out.println(voidCompletableFuture.get() + "-返回值 执行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println("--无返回参数,默认线程池 结束--");
        System.out.println();
        System.out.println();
        
        // 无返回参数,使用自定义线程
        System.out.println("--无返回参数,使用自定义线程 开始--");
        CompletableFuture<Void> voidCompletablePoolFuture = CompletableFuture.runAsync(() -> {

            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },executorService);
        startTime = System.currentTimeMillis();
        System.out.println(voidCompletablePoolFuture.get() + "-返回值 执行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println("--无返回参数,使用自定义线程 结束--\t\t\t");
        System.out.println();
        System.out.println();

        // 有返回参数,默认线程池
        System.out.println("--有返回参数,默认线程池 开始--");
        CompletableFuture<String> objectCompletableFuture = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "helllo supplyasync";
        });
        startTime = System.currentTimeMillis();
        System.out.println(objectCompletableFuture.get() + "-返回值 执行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println("--有返回参数,默认线程池 结束--\t\t\t");
        System.out.println();
        System.out.println();

        // 有返回参数,使用自定义线程
        System.out.println("--有返回参数,使用自定义线程 开始--");
        CompletableFuture<String> objectCompletablePoolFuture = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "helllo supplyasync";
        },executorService);
        startTime = System.currentTimeMillis();
        System.out.println(objectCompletablePoolFuture.get() + "-返回值 执行了" + (System.currentTimeMillis() - startTime) + "毫秒");
        System.out.println("--有返回参数,使用自定义线程 结束--\t\t\t");

        executorService.shutdown();
    }

减少阻塞和轮询whenCompleta

        CompletableFuture通过whenComplete减少阻塞和轮询(回调)

public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName()+"--------副线程come in");
            // 产生随机数
            int result = ThreadLocalRandom.current().nextInt(10);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int t = 6/0;
            return result;
        }).whenComplete((v,e) -> {
            // 不管有没有异常,都会进到这个方法中,v是值,e是异常
            System.out.println("------------------进入到whenComplete方法,v = " + v);
        }).exceptionally(e->{
            // 有异常的情况
            e.printStackTrace();
            System.out.println("异常情况"+e.getCause()+"\t"+e.getMessage());
            return null;
        });

        //线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
        System.out.println(Thread.currentThread().getName()+"线程先去忙其他任务");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

 

CompletableFuture常用API

1、获得结果和触发计算

获取结果

// 不见不散,容易阻塞
public T get() 

// 过时不候,超过时间会抛异常
public T get(long timeout,TimeUnit unit) 

//  类似于get(),区别在于是否需要抛出异常
public T join()

// 立即获取结果不阻塞;
// 计算完,返回计算完成后的结果;
// 没算完,返回设定的valueAbsent(直接返回了备胎值xxx)
public T getNow(T valueIfAbsent)
public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 执行需要2秒
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        long startTime = System.currentTimeMillis();
        // 活立即返回结果,如果future先执行完成返回的是future返回值,否则返回的是valueIfAbsent
        System.out.println("getNow返回值" + future.getNow("xxx"));
        System.out.println("执行了 "+ (System.currentTimeMillis() - startTime) +" 毫秒");
}

//---------------
getNow返回值xxx
执行了 3 毫秒
//---------------

public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 执行需要2秒
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        long startTime = System.currentTimeMillis();
        try {
            //等待需要1秒
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 活立即返回结果,如果future先执行完成返回的是future返回值,否则返回的是valueIfAbsent
        System.out.println("getNow返回值" + future.getNow("xxx"));
        System.out.println("执行了 "+ (System.currentTimeMillis() - startTime) +" 毫秒");

}
//---------------
getNow返回值abc
执行了 3005 毫秒
//---------------

主动触发计算

// 是否立即打断get()方法返回括号值
// 返回true表示打断了获取这个过程,直接返回了备胎值value
// 如果没打断,返回false 和原来方法返回
public boolean complete(T value)
public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 执行需要2秒
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        long startTime = System.currentTimeMillis();
        try {
            // 睡眠时间为小于future时间 输出 true	completeValue
            // 睡眠时间为大于future时间 输出 false	abc
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //执2-等1 返回true+备胎值completeValue
        System.out.println(future.complete("completeValue") + "\t" + future.join());
        System.out.println("执行了 "+ (System.currentTimeMillis() - startTime) +" 毫秒");
    }

2、对计算结果进行处理

thenApply 计算结果存在依赖关系,使得线程串行化。因为依赖关系,所以一旦有异常,后面的thenApply不再执行。

public static void main(String[] args) throws ExecutionException, InterruptedException{
        //当一个线程依赖另一个线程时用 thenApply 方法来把这两个线程串行化,
        CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("111");
            return 1024;
        }).thenApply(f -> {
            // 异常情况:那步出错就停在那步。
            int age = 10/0;
            System.out.println("222");
            return f + 1;
        }).thenApply(f -> {
            // 前面的thenApply异常后就不会进入到该方法
            System.out.println("333");
            return f + 1;
        }).whenCompleteAsync((v,e) -> {
            // 该方法怎么都会进入
            System.out.println("*****v: " + v);
        }).exceptionally(e -> {
            // 抛异常才会进入
            e.printStackTrace();
            return null;
        });

        System.out.println("-----主线程结束,END");
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    }

handle 类似于thenApply,但是又异常的话仍然可以下一步。

public static void main(String[] args) throws ExecutionException, InterruptedException{
        //当一个线程依赖另一个线程时用 handle 方法来把这两个线程串行化,
        // 异常情况:有异常也可以往下一步走,根据带的异常参数可以进一步处理
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1024;
        }).handle((f, e) -> {
            int age = 10 / 0;//异常语句
            System.out.println("222");
            return f + 1;
        }).handle((f, e) -> {
            System.out.println("333");
            return Objects.isNull(f) ? null : (f + 1);
        }).whenCompleteAsync((v, e) -> {
            System.out.println("*****v: " + v);
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });

        System.out.println("-----主线程结束,END");
        System.out.println("future返回值:" + future.join());
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
    }

-----主线程结束,END
111
333
*****v: null
future返回值:null

3、对计算结果进行消费

接收任务的处理结果,并消费处理,无返回结果|消费型函数接口

thenRun

        thenRun(Runnable runnable)

        没有入参,没有返回值;任务A执行完执行任务B,并且任务B不需要A的入参,也没有反参;

thenAccept

        thenAccept(Consumer action)

        有入参,没有返回值;任务A执行完执行任务B,B需要A的结果,但是任务B无返回值

thenApply

        thenApply(Function fn)

        有入参,有返回值;

public static void main(String[] args){
        // null
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());

        // resultA打印出来的 null因为没有返回值
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(System.out::print).join());

        //resultA resultB 返回值
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB").join());
    }

4、CompleteFuture和线程池说明

上面的几个方法都有一般和后面加Async的版本

thenRunthenRunAsync为例,有什么区别?

结论:

        1、没有传入自定义线程池,使用默认线程池ForkJoinPool

        2、调用thenRun第二个任务和前一个任务使用同一个线程池;使用thenRunAsync执行第二个任务的时候,第一个使用的是传入的线程池,第二个使用的是默认的ForkJoinPool线程池。

注意:有可能处理太快,系统优化切换原则,直接使用main线程池处理,如下:

public static void main(String[] args){
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(()->{
            System.out.println("1号任务"+"\t"+Thread.currentThread().getName());
            return "abcd";
        },threadPool).thenRun(()->{
            System.out.println("2号任务"+"\t"+Thread.currentThread().getName());
        }).thenRun(()->{
            System.out.println("3号任务"+"\t"+Thread.currentThread().getName());
        }).thenRun(()->{
            System.out.println("4号任务"+"\t"+Thread.currentThread().getName());
        });

        threadPool.shutdown();
    }

1号任务	pool-1-thread-1
2号任务	main
3号任务	main
4号任务	main

由以下代码可以看出,thenRun会沿用之前任务使用的线程池,而thenRunAsync是使用默认的线程池

 public static void main(String[] args){
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(()->{
            try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("1号任务"+"\t"+Thread.currentThread().getName());
            return "abcd";
        },threadPool).thenRun(()->{
            try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("2号任务"+"\t"+Thread.currentThread().getName());
        }).thenRunAsync(()->{
            try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("3号任务"+"\t"+Thread.currentThread().getName());
        }).thenRun(()->{
            try {TimeUnit.MILLISECONDS.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("4号任务"+"\t"+Thread.currentThread().getName());
        });

        try {TimeUnit.MILLISECONDS.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}
        threadPool.shutdown();
    }

1号任务	pool-1-thread-1
2号任务	pool-1-thread-1
3号任务	ForkJoinPool.commonPool-worker-1
4号任务	ForkJoinPool.commonPool-worker-1

5、对计算速度进行选用

applyToEither方法,那个快使用那个线程的结果

public static void main(String[] args) throws ExecutionException, InterruptedException{
        CompletableFuture<String> play1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
            return "play1 ";
        });

        CompletableFuture<String> play2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            return "play2";
        });

        //对计算速度进行选用
        CompletableFuture<String> thenCombineResult = play1.applyToEither(play2, f -> f + " is winner");

        System.out.println(Thread.currentThread().getName() + "\t" + thenCombineResult.get());
    }

ForkJoinPool.commonPool-worker-1	---come in 
ForkJoinPool.commonPool-worker-2	---come in 
main	play2 is winner

6、对计算结果进行合并

thenCombine 合并:将两个运算结果交给thenCombine来处理

public static void main(String[] args) throws ExecutionException, InterruptedException{
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return 10;
        });

        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return 20;
        });

        CompletableFuture<Integer> thenCombineResult = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return x + y;
        });

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

ForkJoinPool.commonPool-worker-1	---come in 
ForkJoinPool.commonPool-worker-1	---come in 
main	---come in 
30

7、CompletableFuture.anyOf 选择执行最快的

public static void main(String[] args){
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
           try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
           return  "A";
        });
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "B";
        });
        CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "C";
        });
        CompletableFuture<String> futureD = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "D";
        });

        long startTime = System.currentTimeMillis();
        // 选择执行最快的
        CompletableFuture<Object> future = CompletableFuture.anyOf(futureA, futureB, futureC, futureD);
        System.out.println(future.join());
        long endTime = System.currentTimeMillis();
        System.out.println("----执行了" + (endTime - startTime) + "毫秒");

    }


B
----执行了1013毫秒

8、CompletableFuture.allOf 所有任务执行完毕

public static void main(String[] args){
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
           try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
           return  "A";
        });
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "B";
        });
        CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "C";
        });
        CompletableFuture<String> futureD = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            return  "D";
        });

        long startTime = System.currentTimeMillis();
        // 所有任务执行完毕
        CompletableFuture.allOf(futureA, futureB, futureC, futureD).join();
        long endTime = System.currentTimeMillis();
        System.out.println("----执行了" + (endTime - startTime) + "毫秒");
    }


----执行了3004毫秒

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`CompletableFuture`是Java 8中引入的一个非常强大的工具,用于处理异步计算和并行执行。它提供了一种线程安全的方式来处理异步操作的结果,简化了回调地狱。以下是一个简单的范例,展示如何使用`CompletableFuture`执行异步任务: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class CompletableFutureExample { public static void main(String[] args) throws ExecutionException, InterruptedException { // 创建一个异步任务 CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println("开始计算"); // 模拟耗时操作,这里我们只是简单休眠 Thread.sleep(2000); return "异步任务的结果"; }); // 主线程继续执行,不会阻塞 System.out.println("主线程正在执行其他任务..."); // 当异步任务完成后,获取结果 String result = future.get(); // 或者用future.thenApply(result -> ...) System.out.println("最终结果: " + result); } } ``` 在这个例子中: 1. `CompletableFuture.supplyAsync()`方法创建了一个异步任务,它在后台线程中执行,返回一个`CompletableFuture`对象。 2. `Thread.sleep(2000)`模拟了一个延迟执行的任务,实际应用中可能是数据库查询、网络请求等耗时操作。 3. `future.get()`会阻塞,直到异步任务完成并获取结果。如果不希望阻塞,可以使用`thenApply()`、`thenAccept()`或`thenRun()`等方法来处理结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭吱吱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值