使用线程池的好处:
1、降低资源的消耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
2、提高响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务
的状态,当任务来时无需创建新的线程就能执行
3、提高线程的可管理性
线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来
的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使
用线程池进行统一分配
以下代码首先创建线程池executor
,将其传入异步编排对象CompletableFuture
,它提供了四个静态方法来创建一个异步操作。
1、创建异步对象方法
1、runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池
public class Thread1Test {
public static ExecutorService executor = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("方法开始。。。");
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println(i);
}, executor);
System.out.println("方法结束");
}
}
2、计算完成时回调方法
使用supplyAsync
可以获得线程运行返回结果:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果"+i);
return i;
}, executor);
Integer integer = future.get();
提供了计算完成时回调方法,在处理完成后,对结果进行操作:
whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池
来进行执行。
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程
执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
whenComplete
可以得到任务完成结果,参数1是结果,参数2是异常:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果"+i);
return i;
}, executor).whenComplete((res,excption)->{
System.out.println("异步完成,结果是"+res+"异常是:"+excption);
});
这里制造除数为0的异常:
exceptionally
虽然能得到异常信息,但是没法修改返回数据,感知异常,返回默认值
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果"+i);
return i;
}, executor).whenComplete((res,excption)->{
System.out.println("异步完成,结果是"+res+"异常是:"+excption);
}).exceptionally(throwable -> {
//感知异常,返回默认值
return 10;
});
Integer integer = future.get();
3、handle方法
handle和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println(i);
return i;
}, executor).handle((res,thr)->{
if (res!=null){
return res *2;
}
if (thr!=null){
return 0;
}
return 1;
});
4、线程串行化方法
thenApply
方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前
任务的返回值。
thenAccept
方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun
方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行
thenRun 的后续操作
带有 Async 是多开一个线程,是异步执行的。同之前。
以上都要前置任务成功完成。
//线程串行化
/* 1、 thenRunAsync 不能获取上一步的执行结果
2、 thenAcceptAsync 能接受上一步结果,但无返回值
3、 thenApplyAsync能接受上一步结果,有返回值
* */
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("运行结果"+i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("任务2启动了" + res);
return "hello" + res;
}, executor);
5、两任务组合 - 都要完成
两个任务必须都完成,触发该任务。
runAfterBoth
:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后,
处理该任务。
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("任务1线程结束"+i);
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程" + Thread.currentThread().getId());
System.out.println("任务2线程结束");
return "hello";
}, executor);
future01.runAfterBothAsync(future02,()->{
System.out.println("任务3开始");
},executor);
System.out.println("方法结束");
thenAcceptBoth
:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有
返回值。
future01.thenAcceptBothAsync(future02,(f1,f2)->{
System.out.println("任务3开始...之前的结果"+f1+f2);
},executor);
thenCombine
:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
return "组合处理任务1、2的结果" + f1 + f2 + "999";
}, executor);
6、两任务组合 - 一个完成
runAfterEither
:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返
回值。
future01.runAfterEitherAsync(future02,()->{
System.out.println("任务3开始前的结果");
},executor);
acceptEither
:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
future01.acceptEitherAsync(future02,(res)->{
System.out.println("任务3开始前的结果"+res);
},executor);
applyToEither
:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
CompletableFuture<String> eitherAsync = future01.applyToEitherAsync(future02, (res) -> {
System.out.println("任务3开始前结果" + res);
return res.toString() + "--->" + "ke";
}, executor);
System.out.println("方法结束"+eitherAsync.get());
7、多任务组合
allOf
:等待所有任务完成
CompletableFuture<String> img = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品信息");
return "hello.jpg";
},executor);
CompletableFuture<String> attr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询属性信息");
return "黑丝";
},executor);
CompletableFuture<String> desc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品介绍");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "油量";
},executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(img, attr, desc);
allOf.get();
System.out.println("任务结束"+img.get()+attr.get()+desc.get());
anyOf
:只要有一个任务完成
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(img, attr, desc);