Future类的使用

FutureTask

FutureTask实现了RunnableFuture接口,RunnableFuture接口同时实现了Runnable接口和Future接口,所以FutureTask同时具有Future和Runnable的功能。

在这里插入图片描述

FutureTask有两个构造方法,分别传入的是Callable和Runnable,当传入为runnalbe时,可以指定运行结果。若不需要运行结果,则可指定result为null。

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
	public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

FutureTask的使用

1.FutureTask+Thread

因为FutureTask实现了接口Runnable的功能,所以FutureTask可以直接被Thread执行

public class demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        fun1();
    }
    static void fun1() throws ExecutionException, InterruptedException {
        Task task = new Task();
        FutureTask<String> future = new FutureTask<>(task);
        Thread thread = new Thread(future);
        thread.start();
        System.out.println(future.get());
    }
}
class Task implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("done");
        return "ok";
    }
}
/*输出:
done
ok
*/
2.Future+ExecutorService

将callable的执行结果赋给future

public class demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        fun2();
    }
    static void fun2() throws ExecutionException, InterruptedException {
        Task task = new Task();
        ExecutorService es = Executors.newCachedThreadPool();
        //通过future获取线程池得到的结果
        Future<String> future = es.submit(task);
        String result = future.get();
        System.out.println(result);
    }
}
class Task implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("done");
        return "ok";
    }
}
3.FutureTask+ExecutorService

将FutureTask任务提交给线程池执行

    static void fun3() throws ExecutionException, InterruptedException {
        Task task = new Task();
        FutureTask future = new FutureTask<>(task);
        ExecutorService es = Executors.newCachedThreadPool();
        //将FutureTask提交给线程池执行
        es.submit(future);
        String result = (String) future.get();
        System.out.println(result);
    }
}

传统Future的get操作会阻塞等待,系统的吞吐量很难提高,为了解决这个问题,Guava工具包提供了扩展的ListenableFuture,之后在jdk1.8中官方也提供了类似的类,CompletableFuture。

ListenableFuture

ListenableFuture是一个接口,继承了JDK的Future接口,添加了void addListener(Runnable listener,Executor executor)方法。

ListenableFuture使用

  • 创建

首先通过MoreExecutors类的静态方法listeningDecorator方法初始化一个ListeningExecutorService,然后用此实例的submit方法即可初始化ListenableFuture对象。guava的接口ListeningExecutorService继承了jdk原生ExecutorService接口,重写了submit方法,修改返回值类型为ListenableFuture

ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
ListenableFuture<String>listenableFuture = executorService.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        return "ok";
    }
});
//真正干活的线程池
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
        5,
        5,
        0,
        TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(100),
        new CustomizableThreadFactory("demo"),
        new ThreadPoolExecutor.DiscardPolicy());
//guava的接口ListeningExecutorService继承了jdk原生ExecutorService接口,重写了submit方法,修改返回值类型为ListenableFuture
ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(poolExecutor);

//获得一个随着jvm关闭而关闭的线程池,通过Runtime.getRuntime().addShutdownHook(hook)实现
//修改ThreadFactory为创建守护线程,默认jvm关闭时最多等待120秒关闭线程池,重载方法可以设置时间
ExecutorService newPoolExecutor = MoreExecutors.getExitingExecutorService(poolExecutor);

//只增加关闭线程池的钩子,不改变ThreadFactory
MoreExecutors.addDelayedShutdownHook(poolExecutor, 120, TimeUnit.SECONDS);
  • 添加监听(addListener)

Future中的任务执行完后会执行addListener中的任务

listenableFuture.addListener(new Runnable() {
    @Override
    public void run() {
        System.out.println("listen success");
    }
},executorService);
  • 添加回调(Futures.addCallBack)

addListener不支持直接获取返回值,通过Futures.addCallBack可以直接获取返回值。

 Futures.addCallback(listenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String result) {
                System.out.println(result);
                System.out.println("无异常,执行成功");
            }
            @Override
            public void onFailure(Throwable t) {
                System.out.println("有异常,执行失败");
            }
        },executorService);

如果submit的任务能够正常则进入到onSuccess中,如果有异常则进入到onFailure中。addCallback中第三个参数为线程池,这个参数在缺省时为oreExecutors.directExecutor(),MoreExecutors.directExecutor()返回guava默认的Executor,执行回调方法不会新开线程,所有回调方法都在调用者的线程做,本例中是在主线程中执行。但不加Executor参数的方法已经过时,即将删去。

  • 合并多个Futrure

如果需要合并多个Future的结果,可以使用Futures.allAsList,注意如果任何一个Future在执行时出现了异常,都会只执行onFailure方法。Futures.successfulAsList方法则可以将失败或者取消的Future结果用null替代,不会让程序进入onFailure方法。

ListenableFuture<Integer> future1 = executorService.submit(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        return 1;
    }
});
ListenableFuture<Integer> future2 = executorService.submit(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        return 5;
    }
});
ListenableFuture<List<Object>> futures = Futures.allAsList(future1,future2);
Futures.addCallback(futures, new FutureCallback<List<Object>>() {
    @Override
    public void onSuccess(@Nullable List<Object> result) {
        System.out.println(result);
    }
    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
},executorService);
  • 返回值转换

如果需要对返回值做处理,可以使用Futures.transform方法,它是同步方法,还有一个异步方法Futures.transformAsync

ListenableFuture<String> task3 = executorService.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        return "task3";
    }
});
ListenableFuture<Integer> task4 = Futures.transform(task3, new Function<String, Integer>() {
    @Nullable
    @Override
    public Integer apply(@Nullable String input) {
        return 2;
    }
},executorService);
Futures.addCallback(task4, new FutureCallback<Integer>() {
    @Override
    public void onSuccess(@Nullable Integer result) {
        System.out.println(result);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
},executorService);

11Futures.transform()和Futures.addCallback()都是对addListener做了封装,进行回调的设置,但是transform更适合用在链式处理的中间过程,addCallback更适合用在处理最终的结果上。

CompletableFuture

CompletableFuture是jdk8的新特性。CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步会点、流式处理、多个Future组合处理的能力。

创建异步任务

supplyAsync

supplyAsync是创建带有返回值的异步任务,一种是使用默认线程池ForkJoinPool.commonPool(),另一种是使用自定义的线程池。

//默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
    return asyncSupplyStage(ASYNC_POOL, supplier);
}
//自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                   Executor executor) {
    return asyncSupplyStage(screenExecutor(executor), supplier);
}

例:

默认线程池

   static void fun3() throws ExecutionException, InterruptedException {
        CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            return "result";
        });
        //等待任务执行完成
        cf1.get();
    }
//ForkJoinPool.commonPool-worker-9

在使用默认线程池的情况下,如果调用子任务的线程不使用get或者sleep等进行等待,那么可能会在子任务还没有执行完成时,线程池就被关闭了。

自定义线程池:

static void fun4() throws ExecutionException, InterruptedException {
    // 自定义线程池
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println("do something....");
        return "result";
    }, executorService);

    //关闭线程池
    executorService.shutdown();
}
runAsync

runAsync是创建没有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool())的方法,一个是带有自定义线程池的重载方法。

//默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable) {
    return asyncRunStage(ASYNC_POOL, runnable);
}
//自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
}

获取结果的方法

// 如果完成则返回结果,否则就抛出具体的异常
public T get() throws InterruptedException, ExecutionException 
 
// 最大时间等待返回结果,否则就抛出具体异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
 
// 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因
public T join()
 
// 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
public T getNow(T valueIfAbsent)
 
// 如果任务没有完成,返回的值设置为给定值
public boolean complete(T value)
 
// 如果任务没有完成,就抛出给定异常
public boolean completeExceptionally(Throwable ex) 

异步回调处理

thenApply和thenApplyAsync

thenApply 表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值。

thenApply:

static void fun5() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName()+":cf1...");
            return 1;
        });
        CompletableFuture<Integer> cf = cf1.thenApply((result) -> {
            System.out.println(Thread.currentThread().getName()+":cf2");
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result + 2;
        }).thenApply(res -> {
            System.out.println(Thread.currentThread().getName()+":cf3");
            return res +2 ;
        }).thenApply(res -> {
            System.out.println(Thread.currentThread().getName() + ":cf4");
            return res + 2;
        });
        //等待任务1执行完成
        System.out.println("cf1结果->" + cf1.get());
        //等待任务2执行完成
        System.out.println("cf结果->" + cf.get());

    }
ForkJoinPool.commonPool-worker-9:cf1...
ForkJoinPool.commonPool-worker-9:cf2
cf1结果->1
ForkJoinPool.commonPool-worker-9:cf3
ForkJoinPool.commonPool-worker-9:cf4
cf结果->7

thenApplyAsync:

static void fun6() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName()+":cf1...");
        return 1;
    });
    CompletableFuture<Integer> cf = cf1.thenApplyAsync((result) -> {
        System.out.println(Thread.currentThread().getName()+":cf2");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result + 2;
    }).thenApplyAsync(res -> {
        System.out.println(Thread.currentThread().getName()+":cf3");
        return res +2 ;
    }).thenApplyAsync(res -> {
                System.out.println(Thread.currentThread().getName() + ":cf4");
                return res + 2;
            });
    //等待任务1执行完成
    System.out.println("cf1结果->" + cf1.get());
    //等待任务2执行完成
    System.out.println("cf结果->" + cf.get());
}
ForkJoinPool.commonPool-worker-9:cf1...
ForkJoinPool.commonPool-worker-2:cf2
cf1结果->1
ForkJoinPool.commonPool-worker-2:cf3
ForkJoinPool.commonPool-worker-2:cf4
cf结果->7

两者的区别为:使用thenAccep方法时子任务与父任务使用的是同一个线程或调用线程,而thenAccepAsync在子任务中可能(有时也可能也是使用父任务的线程)是另起一个线程执行任务,并且thenAccepAsync可以自定义线程池,默认的使用ForkJoinPool.commonPool()线程池,如果传入第二个参数可指定线程池,任务将在线程池中进行。

thenAccept和thenAcceptAsync

thenAccep表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,无返回值。

thenRun和thenRunAsync

thenRun表示某个任务执行完成后执行的动作,即回调方法,无入参,无返回值。

static void fun8() throws ExecutionException, InterruptedException {
        Executor executor = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " cf1 do something....");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });
        CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " cf2 do something....");
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },executor).thenRunAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " cf3 do something....");
        },executor);

        //等待任务1执行完成
        System.out.println("cf1结果->" + cf1.get());
        //等待任务2执行完成
        System.out.println("cf2结果->" + cf2.get());
    }
ForkJoinPool.commonPool-worker-9 cf1 do something....
pool-1-thread-1 cf2 do something....
pool-1-thread-2 cf3 do something....
cf1结果->1
cf2结果->null
whenComplete和whenCompleteAsync

whenComplete是当某个任务执行完成后执行的回调方法,会将执行结果和执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null。回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。

static void fun9() throws InterruptedException {
    
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " cf1 do something....");
        int a = 1/0;
        return 1;
    });

    CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {
        System.out.println("上个任务结果:" + result);
        System.out.println("上个任务抛出异常:" + e);
        System.out.println(Thread.currentThread().getName() + " cf2 do something....");
        //抛一个异常
        throw new IllegalArgumentException();
    });
    //等待任务2执行完成
    cf2.join();
}
ForkJoinPool.commonPool-worker-9 cf1 do something....
上个任务结果:null
上个任务抛出异常:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
ForkJoinPool.commonPool-worker-9 cf2 do something....
Exception in thread "main" java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:283)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1603)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)
	Suppressed: java.lang.IllegalArgumentException
		at demo.StreamDemo.Demo4.lambda$fun9$19(Demo4.java:176)
		at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
		at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
		at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
		at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1705)
		... 4 more
Caused by: java.lang.ArithmeticException: / by zero
	at demo.StreamDemo.Demo4.lambda$fun9$18(Demo4.java:167)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
	... 4 more

Process finished with exit code 1

handle和handleAsync

和whenComplete基本一致,区别在于handle的回调方法有返回值。

不带Async的方法使用的线程

关于不带Async的方法,使用的是调用线程还是父任务执行的线程需要进行分析

结论:以whenComplete为例,当调用线程执行到whenComplete方法时,如果父方法已经complete,那么将会通过调用线程执行whenComplete方法。如果调用线程执行到whenComplete方法时,父方法还未complete,那么将会通过父方法的线程执行whenComplete方法。

static void fun10(){
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " cf1 do something....");
        return 1;
    });
    //主线程睡眠时,cf1的任务已经执行完了
    try {
        Thread.sleep(100);
    } catch (InterruptedException interruptedException) {
        interruptedException.printStackTrace();
    }
    //因为cf1在执行到whenComplete之前就已经执行完了,所以when中的方法由main执行
   
    CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {
        System.out.println("上个任务结果:" + result);
        System.out.println("上个任务抛出异常:" + e);
        System.out.println(Thread.currentThread().getName() + " cf2 do something....");
    });
}
ForkJoinPool.commonPool-worker-9 cf1 do something....
上个任务结果:1
上个任务抛出异常:null
main cf2 do something....
static void fun10() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " cf1 do something....");
        try {
            Thread.sleep(100);
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
        return 1;
    });

    CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {
        System.out.println("上个任务结果:" + result);
        System.out.println("上个任务抛出异常:" + e);
        System.out.println(Thread.currentThread().getName() + " cf2 do something....");
    });
    //等待cf2执行完
    cf2.get();
}
ForkJoinPool.commonPool-worker-9 cf1 do something....
上个任务结果:1
上个任务抛出异常:null
ForkJoinPool.commonPool-worker-9 cf2 do something....
捕捉产生的异常exceptionally
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)

在用CompletableFuture编写多线程时,如果需要处理异常,可以用exceptionally,它的作用相当于catch。

exceptionally的特点:

当出现异常时,会触发回调方法exceptionally
exceptionally中可指定默认返回结果,如果出现异常,则返回默认的返回结果

public class FutureExceptionTest {

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

        CompletableFuture<String> orgFuture = CompletableFuture.supplyAsync(
                ()->{
                    System.out.println("当前线程名称:" + Thread.currentThread().getName());
                    throw new RuntimeException();
                }
        );

        CompletableFuture<String> exceptionFuture = orgFuture.exceptionally((e) -> {
            e.printStackTrace();
            return "你的程序异常啦";
        });

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

多任务组合处理

thenCombine、thenAcceptBoth 和runAfterBoth

这三个方法都是将两个CompletableFuture组合起来处理,只有两个任务都正常完成时,才进行下阶段任务。

区别:thenCombine会将两个任务的执行结果作为所提供函数的参数,且该方法有返回值;thenAcceptBoth同样将两个任务的执行结果作为方法入参,但是无返回值;runAfterBoth没有入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。

static void fun11() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " cf1 do something....");
        return 1;
    });
    CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " cf2 do something....");
        return 2;
    });
    CompletableFuture<Integer> cf3 = cf1.thenCombine(cf2,(a,b) ->{
       return a+b;
    });
    System.out.println(cf3.get());
}
ForkJoinPool.commonPool-worker-2 cf2 do something....
ForkJoinPool.commonPool-worker-9 cf1 do something....
3

注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果。如果两个都有异常,那么cf3.get()得到的是调用then时得到的异常,如上例则为cf1中的异常

applyToEither、acceptEither和runAfterEither

这三个方法和上面一样也是将两个CompletableFuture组合起来处理,当有一个任务正常完成时,就会进行下阶段任务。

区别:applyToEither会将已经完成任务的执行结果作为所提供函数的参数,且该方法有返回值;acceptEither同样将已经完成任务的执行结果作为方法入参,但是无返回值;runAfterEither没有入参,也没有返回值。

CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " cf1 do something....");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "cf1 任务完成";
        });

        CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " cf2 do something....");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "cf2 任务完成";
        });

        CompletableFuture<String> cf3 = cf1.applyToEither(cf2, (result) -> {
            System.out.println("接收到" + result);
            System.out.println(Thread.currentThread().getName() + " cf3 do something....");
            return "cf3 任务完成";
        });

        System.out.println("cf3结果->" + cf3.get());
    }
ForkJoinPool.commonPool-worker-1 cf1 do something....
ForkJoinPool.commonPool-worker-2 cf2 do something....
接收到cf1 任务完成
ForkJoinPool.commonPool-worker-1 cf3 do something....
cf3结果->cf3 任务完成
allOf和anyOf

allOf:CompletableFuture是多个任务都执行完成后才会执行,只有有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。

anyOf :CompletableFuture是多个任务只要有一个任务执行完成,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回执行完成任务的结果。

static void fun6() throws ExecutionException, InterruptedException {
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() ->{
        try {
            System.out.println(Thread.currentThread().getName() + " cf1 do something....");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("cf1 任务完成");
        return "cf1 任务完成";
    });
    CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " cf2 do something....");
            int a = 1/0;
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("cf2 任务完成");
        return "cf2 任务完成";
    });

    CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + " cf2 do something....");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("cf3 任务完成");
        return "cf3 任务完成";
    });
    CompletableFuture<Void> cfAll = CompletableFuture.allOf(cf1, cf2, cf3);
    System.out.printf("", cfAll.get());
}
结果
ForkJoinPool.commonPool-worker-1 cf1 do something....
ForkJoinPool.commonPool-worker-2 cf2 do something....
ForkJoinPool.commonPool-worker-3 cf2 do something....
cf1 任务完成
cf3 任务完成
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
	at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
	at com.npr.javastudy.Demo3.fun6(Demo3.java:176)
	at com.npr.javastudy.Demo3.main(Demo3.java:26)
Caused by: java.lang.ArithmeticException: / by zero
	at com.npr.javastudy.Demo3.lambda$fun6$15(Demo3.java:156)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1596)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1067)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1703)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:172)

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值