线程池与异步回调
线程池
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
2,//核心线程数
5,//最大线程数
1,//等待归还最大线程时间
TimeUnit.MINUTES,//等待归还最大线程时间单位
new ArrayBlockingQueue<>(20),//阻塞队列
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.AbortPolicy()//拒绝策略
);
//ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
//LinkedBlockingQueue:由链表结构组成的有界(但大小默认值为integer.MAX_VALUE),不指定队列大小则为无界阻塞队列,指定了大小则为有界队列。
RejectedExecutionHandler rejected = null;
//默认,队列满了丢任务抛出异常
rejected = new ThreadPoolExecutor.AbortPolicy();
//队列满了丢任务不抛异常
rejected = new ThreadPoolExecutor.DiscardPolicy();
//将最早进入队列的任务删,之后再尝试加入队列
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();
//如果添加到线程池失败,那么主线程会自己去执行该任务;如果执行程序已关闭(主线程运行结束),则会丢弃该任务
rejected = new ThreadPoolExecutor.CallerRunsPolicy();
任务类型
比如像加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务,大部分场景下都是纯 CPU 计算。IO 密集型任务:比如像 MySQL 数据库、文件的读写、网络通信等任务,这类任务不会特别消耗 CPU 资源,但是 IO 操作比较耗时,会占用比较多时间。在知道如何判断任务的类别后,让我们分两个场景进行讨论:
CPU 密集型任务:
1.对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 8 核的 CPU,每个核一个线程,理论上创建 8 个线程就可以了。
2.如果设置过多的线程数,实际上并不会起到很好的效果。此时假设我们设置的线程数量是 CPU 核心数的 2 倍,因为计算任务非常重,会占用大量的 CPU 资源,所以这时 CPU 的每个核心工作基本都是满负荷的,
3.而我们又设置了过多的线程,每个线程都想去利用 CPU 资源来执行自己的任务,这就会造成不必要的上下文切换,此时线程数的增多并没有让性能提升,反而由于线程数量过多会导致性能下降。
4.线程的数量 = CPU 核数就是最合适的,不过通常把线程的数量设置为CPU 核数 +1
IO 密集型任务
1.对于 IO 密集型任务最大线程数一般会大于 CPU 核心数很多倍,因为 IO 读写速度相比于 CPU 的速度而言是比较慢的,如果我们设置过少的线程数,就可能导致 CPU 资源的浪费。而如果我们设置更多的线程数,那么当一部分线程正在等待 IO 的时候,它们此时并不需要 CPU 来计算,那么另外的线程便可以利用 CPU 去执行其他的任务,互不影响,这样的话在任务队列中等待的任务就会减少,可以更好地利用资源。
2.线程数 = CPU 核心数 * (1 + IO 耗时秒/ CPU 耗时秒)
异步调用CompletableFuture
//无返回值的异步调用
Future future = CompletableFuture.runAsync(() -> {
},threadPoolExecutor);
//有返回值的异步调用
Future future = CompletableFuture.supplyAsync(() -> {
return “有返回值的异步方法”;
}, poolExecutor);
//有返回值的异步调用,whenComplet上一步调用成功执行方法,可以接收到上一步的返回值和异常,无返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).whenComplete((integer, throwable) -> {
System.out.println(“执行成功执行的方法,可以获取到上一步执行的结果” + integer);
System.out.println(“上一步执行的异常” + throwable);
});
//有返回值的异步调用,handle上一步调用成功执行方法,可以接收到上一步的返回值和异常,有返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).handle((integer, throwable) -> {
System.out.println(“执行成功执行的方法,可以获取到上一步执行的结果” + integer);
System.out.println(“上一步执行的异常” + throwable);
return 2;
});
//有返回值的异步调用,exceptionally上一步调用时发生异常执行方法,有返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).exceptionally(throwable -> {
return 2;
});
//thenRun上一步调用成功执行的方法,无法接受到上一步的结构,无返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).thenRun(() -> {
});
//thenAccept上一步调用成功执行的方法,可以接受到上一步的结构,无返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).thenAccept(integer -> {
System.out.println(“执行成功执行的方法,可以获取到上一步执行的结果” + integer);
});
//thenApply上一步调用成功执行的方法,可以接受到上一步的结构,有返回值
Future future = CompletableFuture.supplyAsync(() -> {
return 1;
}, poolExecutor).thenApply(integer -> {
return 2;
});
//组合调用,任务1任务2都完成后执行任务3
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future3 = future1.runAfterBothAsync(future2, () -> {
System.out.println(“任务3执行”);
}, poolExecutor);
//组合调用,任务1任务2都完成后执行任务3,可以获取到任务1任务2的参数,无返回值
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
future1.thenAcceptBothAsync(future2, (s, s2) -> {
}, poolExecutor);
//组合调用,任务1任务2都完成后执行任务3,可以获取到任务1任务2的参数,有返回值
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture stringCompletableFuture = future1.thenCombineAsync(future2, (s, s2) -> {
return “任务1返回” + s + “任务2返回” + s2;
}, poolExecutor);
//组合调用,任务1任务2执行完成一个后执行任务3,无法获取到任务1任务2执行完成的一个参数,无返回值
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
future1.runAfterEitherAsync(future2,() -> {
},poolExecutor);
//组合调用,任务1任务2执行完成一个后执行任务3,可以获取到任务1任务2执行完成的一个参数,无返回值
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture voidCompletableFuture = future1.acceptEitherAsync(future2, command -> {
}, poolExecutor);
//组合调用,任务1任务2执行完成一个后执行任务3,可以获取到任务1任务2执行完成的一个参数,有返回值
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
future1.applyToEitherAsync(future2,s -> {
return “任务3”;
},poolExecutor);
//多任务组合,所有任务全部完成
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture voidCompletableFuture = CompletableFuture.allOf(future1, future2);
voidCompletableFuture.get();
//多任务组合,一个任务全部完成
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
return “任务一”;
}, poolExecutor);
CompletableFuture voidCompletableFuture = CompletableFuture.anyOf(future2)(future1, future2);
voidCompletableFuture.get();
关闭线程池
executorService.shutdown();
try {
if(!executorService.awaitTermination(60, TimeUnit.SECONDS)){
executorService.shutdownNow();
}
} catch (InterruptedException ignore) {
executorService.shutdownNow();
}