异步任务
supplyAsync是创建带有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool
.commonPool())的方法,一个是带有自定义线程池的重载方法
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"在执行");
int i = 1/0;
return 1024;
});
runAsync
创建不包含返回值的异步任务,其他与supplyAsync类似
CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{
System.out.println(Thread.currentThread().getName()+"正在执行");
});
获取任务回调
// 如果完成则返回结果,否则就抛出具体的异常
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)
最后执行的代码块
whenComplete
异步任务的回调完成后执行,下面是函数式接口,第一个参数为回调结果,第二个参数为Exception
new BiConsumer<Integer, Throwable>(){}
//设置回调函数
completableFuture2.whenComplete(new BiConsumer<Integer, Throwable>() {
@Override
public void accept(Integer unused, Throwable throwable) {
System.out.println(unused);
System.out.println(throwable);
}
}).get();
exceptionally
当异步任务中有异常抛出时会执行,函数式接口中只有一个参数为Exception类型
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
Integer result = new Random().nextInt(5);
System.out.println(Thread.currentThread().getName() + "休息一秒钟");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (result < 3) {
int a = 10/0;
}
return result; //这里使用我自己定义的线程池
},executorService).whenComplete((r,e)->{ //r为返回的结果,e则为返回的Exception对象
if (e==null) {
System.out.println("返回的结果为"+r);
}
}).exceptionally(e->{ //最后抛出了异常就会执行的方法
e.printStackTrace();
System.out.println("抛出了异常");
return null;
});
后缀为Async的API
以thenRun和thenRunAsync为例:
①:没有传入自定义的线程池,两种api都会默认使用ForkJoinPool来作为线程池
②:如果在执行第一个任务时 传入了一个自定义线程池,
调用thenRun会和上一个任务共用同一个线程池,
调用thenRunAsync,上一个线程池使用自定义的线程池,下一个任务使用ForkJoinPool线程池
③:执行过快时,系统可能进行优化,直接使用main线程处理
其他api同理
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
System.out.println("hello world"+Thread.currentThread());
},executorService);
cf.thenRunAsync(()->{
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("这是第一个方法"+Thread.currentThread().getName());
}
).thenRun(()->{
try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("这是第二个方法"+Thread.currentThread().getName());
}).thenRun(()->{
try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("这是第三个方法"+Thread.currentThread().getName());
});
System.out.println(cf.join());
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
executorService.shutdown();
顺序执行
thenRun
Runable runnable 接口
任务A执行完执行B,并且B不需要A的结果
thenAccept
Runable runnable 接口
任务A执行完执行B,B需要A的结果,但是B无返回值
thenApply
Runable runnable 接口
任务A执行完执行B,B需要A的结果,同时B有返回值
ExecutorService executorService = Executors.newFixedThreadPool(3);
//CompletableFuture实现多个线程之间的串行化执行
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
System.out.println("111");
return 1;
},executorService).thenApply((a)->{
System.out.println("222");
int i = 1/0;
return a+2;
}).thenApply((a)->{
System.out.println("333");
return a+3;
}).whenComplete((v,e)->{
if (e==null) { //没有发生错误
System.out.println("最终结果是:"+v);
}
}).exceptionally(e->{ //发生了异常执行
e.printStackTrace();
return null;
});
System.out.println("main线程忙其他工作去了");
executorService.shutdown();
handle
handle所需要接口的参数与whenComplete相同,但是handle接口是需要返回值的。同时如果执行过程中出现了异常是不会抛出的。
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
System.out.println("111");
return 1;
},executorService).handle((a,b)->{
System.out.println("222");
int i = 1/0;
return a+2;
})
多任务组合处理
thenCombine
参数需要一个要组合的CompletableFuture对象,和一个(a,b) -> return a+b; 类似的接口,来完成对两个任务结果的合并
CompletableFuture<Integer> theLastResult = CompletableFuture.supplyAsync(()->{
System.out.println("正在进行第一次计算");
return 10;
}).thenCombine(CompletableFuture.supplyAsync(()->{
System.out.println("正在进行第二次计算");
return 20;
}),(a,b)->{
return a+b;
}).thenCombine(CompletableFuture.supplyAsync(()->{
System.out.println("正在进行第三次计算");
return 30;
}),(a,b)->a+b);
//开始获取最后结果
System.out.println("main: 最后结果为" + theLastResult.join());
applyToEither
获取到两个异步任务中先完成任务的回调,参数为 CompeltableFuture和一个Function接口实现类
CompletableFuture<String> playerA = CompletableFuture.supplyAsync(()->{
System.out.println("A come in");
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
return "A";
});
CompletableFuture<String> playerB = CompletableFuture.supplyAsync(()->{
System.out.println("B come in");
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
return "B";
});
//再开一个异步任务比较两个线程之间执行速度的比较
CompletableFuture<String> winner = playerA.applyToEither(playerB, r -> {
return r;
});
//获取最终结果
System.out.println("最终赢家为:"+winner.join());
刚刚学完CompletableFuture,以此总结一番,如果存在错误,欢迎大家提出来