线程池
1、初始化线程的4种方式
1.1、集成Thread类
1.2、实现Runnable接口
1.3、实现Callable接口+FutureTask(可拿到返回结果,可以处理异常)
1.4、线程池 可以控制资源,性能稳定
方式1和方式2:主进程无法获取线程的运算结果。不适合当前场景
方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可导致服务器资源耗尽
方式4:通过如下两种方式初始化线程池
Executors.newFiexedThread(3);
new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeOut,
unit,
workQueue,
threadFactory,
heandler);
通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下。一个异步调用可能会依赖于另一个异步调用的执行结果
2、线程池创建:
2.1、创建线程池
3.1.1、七大参数
corePoolSize:核心线程数(一直存在,除非设置了核心线程数超时时间),线程池创建完毕后就准备就绪的线程数量,就等待来接收异步任务去执行,都是就绪状态,只有在提交任务时就会start;
maximumPoolSize:最大线程数量,最多N个线程同时执行任务。
keepAliveTime:存活时间,当空闲线程数量大于核心数量时,超过这个存活时间后,会释放空闲的线程(maximumPoolSize-maximumPoolSize)=被释放的线程。
unit:时间单位。
workQueue:阻塞队列,用于最大线程被占满,来保存没有被执行的任务,只要有空闲的线程,就会去队列里面取出新的任务继续执行。
threadFactory:线程的创建工厂。
heandler:拒绝策略,按照我们指定的策略处理被阻塞的任务。默认使用丢弃策略
(1)、丢弃最老任务
(2)、。。。。
(3)、直接丢弃任务
(4)、将队头直接丢弃
3.1.2、执行顺序
3.1.2.1、创建好线程池,准备好核心线程,准备接收任务
3.1.2.2、新任务进来,用核心线程执行任务
(1)核心线程满了以后就会进去阻塞队列,空闲的核心线程就会去队列里面去新的任务
(2)阻塞队列满了就会去开启新的线程,最多开启线程数位最大线程数。
(3)如果线程开到最大线程数了,还有任务进来,就会启用我们指定的拒绝策略去处理任务
(4)所有的线程创建都是有我们的线程工厂进行创建
3.1.3、线程池类型
灵活线程池:核心线程数为0,最大线程为Integer最大值,在空闲时间都会被回收;
Executors.newCachedThreadPool();
固定线程池:设置固定线程数,最大线程数和核心线程数一致
Executors.newFixedThreadPool(5);
任务调度线程池:用来做定时任务的
Executors.newScheduledThreadPool()
单线程池:核心和最大都只有1个线程,队列为无界队列,顺序执行
Executors.newSingleThreadExecutor();
CompletableFuture异步编排
说明:多个异步任务运行时可能会依赖于另一个线程的结果
1、runAsync使用方式:没有返回值
CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
//执行代码
}, executor);
2、supplyAsync使用方式:有返回值
CompletableFuture<Object> supplyAsync = CompletableFuture.supplyAsync(() -> {
return null;
}, executor);
3、whenComplete、whenCompleteAsync:在 supplyAsync、runAsync执行完毕后还想做其他任务就可以使用链式调用whenComplete(是指当前任务的线程执行继续执行)、whenCompleteAsync(是重新提交到线程池进行执行),这两个可以接收到成功值或者异常信息,只能作为监听成功或失败。
CompletableFuture<Object> supplyAsync = CompletableFuture.supplyAsync(() -> {
return null;
}, executor).whenComplete((res,exception)->{
System.out.println("结果是:"+res+"异常是:"+exception);
});
4、exceptionally:还可以链式调用exceptionally,可以获取到异常信息并且可以修改最终值
CompletableFuture<Object> supplyAsync = CompletableFuture.supplyAsync(() -> {
return null;
}, executor).whenComplete((res,exception)->{
System.out.println("结果是:"+res+"异常是:"+exception);
}).exceptionally((exception)->{
return 10;
});
5、handle方法:可以接受两个参数(成功值,异常信息),返回一个参数(可以修改最终返回值),相当于方法执行后的处理
CompletableFuture<Integer> handle = CompletableFuture.supplyAsync(() -> {
return 20;
}, executor).handle((res, exception) -> {
if (res!=null){
System.out.println("结果是:" + res);
return res;
}else{
System.out.println("异常是:" + exception);
return 10;
}
});
6、线程串行化方法
统一解释:链式调用方法后不加Async(是指当前任务的线程执行继续执行),加上Async(是重新提交到线程池进行执行)
6.1、thenRun、thenRunAsync方法:是要上面的任务执行完毕后才开始执行此方法的后续操作,无返回结果。
.thenRunAsync(()->{
System.out.println("执行后续操作。。。");
},executor);
6.2、thenAccept、thenAcceptAsync:有一个入参(消费处理结果),接收处理结果进行后续操作,无返回结 果。
.thenAcceptAsync((res)->{
System.out.println("接收到结果:"+res+"执行后续操作。。。");
},executor);
6.3、thenApply、thenApplyAsync:接收返回结果,并进行后续操作,并返回当前任务的返回值。
.thenApplyAsync((res)->{
System.out.println("接收到结果:"+res+"执行后续操作。。。");
return 30;
},executor);
7、两任务组合
统一解释:链式调用方法后不加Async(是指当前任务的线程执行继续执行),加上Async(是重新提交到线程池进行执行)
7.1、thenCombine、thenCombineAsync:组合两个futre的返回结果,并且返回当前任务的返回值
CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1执行完毕!");
return 10;
}, executor);
CompletableFuture<Integer> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2执行完毕");
return 20;
}, executor);
CompletableFuture<Integer> combineAsync = supplyAsync1.thenCombineAsync(supplyAsync2, (res1, res2) -> {
System.out.println("结合任务1和任务2的结果计算出任务3,并返回");
return 30;
}, executor);
7.2、thenAcceptBoth、thenAcceptBothAsync:组合两个futre,然后处理人物,没有返回值
CompletableFuture<Void> acceptBothAsync = supplyAsync1.thenAcceptBothAsync(supplyAsync2, (res1, res2) -> {
System.out.println("结合任务1和任务2的结果执行任务3,没有返回值!");
}, executor);
7.3、thenAfterBoth、thenAfterBothAsync:组合两个futre,不需要返回结果,只需要处理两个Future后执行该任务。
CompletableFuture<Void> afterBothAsync = supplyAsync1.runAfterBothAsync(supplyAsync2, () -> {
System.out.println("任务1和任务2执行完执行任务3.没有返回值!");
}, executor);
8、两个任务组合 完成一个
8.1、applyToEitherAsync、applyToEither
supplyAsync1.applyToEitherAsync(supplyAsync2,(res)->{
System.out.println("只要有一个完成就接收值,处理并返回值!");
return 3;
},executor);
8.2、acceptEitherAsync、acceptEither
supplyAsync1.acceptEitherAsync(supplyAsync2,(res)->{
System.out.println("只要有一个完成就接收值,处理不能返回值!");
},executor);
8.3、runAfterEitherAsync、runAfterEither
supplyAsync1.runAfterEitherAsync(supplyAsync2,()->{
System.out.println("只要有一个完成不接受值,处直接理不能返回值!");
},executor);
9、多任务组合
9.1、allOf:等待所有任务完成
CompletableFuture<Void> all = CompletableFuture.allOf(supplyAsync1, supplyAsync2);
all.get();
9.2、anyOf:只要有一个任务完成
CompletableFuture<Object> all = CompletableFuture.anyOf(supplyAsync1, supplyAsync2);
all.get();//获取的是最快成功的那个数据