几种常见的线程池及适用场景(线程池的创建方式)
几种常见的线程池及适用场景(线程池的创建方式)int maximumPoolSize:线程池允许存在的最大线程数int corePoolSize:核心线程数,线程池创建好就已经准备就绪的线程数 量,等待接收异步任务 ,异步任务进来后,自动执行。核心线程会一直存在,除非设置了allowCoreThreadTimeOut,才允许核心线程超时。代码:public ThreadPoolExecutor(int corePoolSize int maximumPoolSize long keepAliveTime TimeUnit unit BlockingQueue<Runnable> workQueue ThreadFactory threadFactory RejectedExecutionHandler handler) {} 由以上源码知道,当使用Th
1、多线程的四种实现方式多线程的实现方式有四种
- 继承thread类
- 实现runnable接口
- 实现Callable
- 实现Callable不能简单把Callable对象传给thread,要使用FutureTask做一次封装
- get()可以获取到call()返回值
- get()阻塞等待所有线程执行完,才输出
- 线程池
通常在业务代码中前三种都不使用,只使用第四种(线程池) 每个系统通常有一两个线程池,每一个异步任务,提交给线程池执行即可
1.1 提交任务到线程池的两种方式- execute() 返回值为void,代表只执行异步任务,没有返回值
- submit() 返回值为Future,既可以执行任务,野口接收返回值。
- 继承thread和实现runnable接口的方式,无法得到返回值,实现callable接口可以得到返回值。
- 前三种方式都无法控制资源,即来一个线程就要创建一个线程,容易使系统资源耗尽
- 线程池的方式可以控制资源,系统性能稳定。
- 降低资源消耗。 可以重复利用已经创建好的线程,降低线程的创建和销毁带来的损耗。
- 提高响应速度。 因为线程池中的线程都处于等待分配任务状态,当任务过来时可以直接执行。
- 提高线程的可管理性。 如果是单cpu的话,创建多个线程,会导致资源耗尽,但是线程池有拒绝策略;另外还可以核心业务和非核心业务两种线程池,如果某个时间内存压力大,可以释放掉非核心业务线程池。使用线程池就可以使线程的管理方便。
ThreadPoolExecutor属于原生的创建方式,其他的线程池创建方式都是封装了ThreadPoolExecutor类。
ThreadPoolExecutor继承关系图下图
代码:
public ThreadPoolExecutor(int corePoolSize
int maximumPoolSize
long keepAliveTime
TimeUnit unit
BlockingQueue<Runnable> workQueue
ThreadFactory threadFactory
RejectedExecutionHandler handler) {}
由以上源码知道,当使用ThreadPoolExecutor创建线程时,需要传入七大参数!
3.使用Executors创建线程Executors创建线程,其底层还是用的是ThreadPoolExecutor创建的。
3.1 Executors创建线程的分类- Executors.newFixedThreadPool(10) :固定大小 core = 自定义的线程数,但阻塞队列是无界队列,会OOM内存溢出
- Executors.newCachedThreadPool(); core是0,最大线程数无限大,无限创建线程的话,会使cpu占用100%,因为cpu要不停的调度线程去执行任务
- Executors.newSingleThreadExecutor(); 单线程的线程池,后台从队列里取,挨个执行。阻塞队列是无界队列,会OOM内存溢出
- Executors.newScheduledThreadPool(); 带有定时任务的线程池
int corePoolSize:核心线程数,线程池创建好就已经准备就绪的线程数 量,等待接收异步任务 ,异步任务进来后,自动执行。核心线程会一直存在,除非设置了allowCoreThreadTimeOut,才允许核心线程超时。
int maximumPoolSize:线程池允许存在的最大线程数
long keepAliveTime:超时时间。如果当前线程数量大于核心数量,且在keepAliveTime时间内保持空闲,就释放掉。 释放的是最大线程数 - 核心线程数
TimeUnit unit: 超时时间单位
BlockingQueue workQueue:阻塞队列,如果线程有很多,就会把线程保存在队列里 只要线程有空闲,就去阻塞队列中取。 分类见下文。
ThreadFactory threadFactory:线程的创建工厂
RejectedExecutionhandler handler:拒绝策略 ,如果线程满了采取的策略
拒绝策略分类:
- DiscardOldestPolicy 抛弃掉最早进入的线程
- DiscardPolicy 抛弃掉最新的线程
- DiscardPolicy 剩余的线程调用run方法,变为同步执行
- DiscardPolicy 抛弃掉最新的线程,并抛出异常!
工作顺序
- 线程池创建,准备好核心线程core数,准备接受任务
- 核心线程core满了,就将再进来的任务放入阻塞队列中,空闲的core就回去阻塞队列中获取任务执行
- 阻塞队列满了,就直接开新线程,最大只能开到max执行的数量
- max线程数满了,采用拒绝策略拒绝新来的任务
- 当任务量减轻,max - core剩余的线程在keepAliveTime时间后,释放掉内存
我们知道队列是先进先出的。当放入一个元素的时候,会放在队列的末尾,取出元素的时候,会从队头取。那么,当队列为空或者队列满的时候怎么办呢。
这时,阻塞队列,会自动帮我们处理这种情况。
当阻塞队列为空的时候,从队列中取元素的操作就会被阻塞。当阻塞队列满的时候,往队列中放入元素的操作就会被阻塞。
而后,一旦空队列有数据了,或者满队列有空余位置时,被阻塞的线程就会被自动唤醒。
这就是阻塞队列的好处,你不需要关心线程何时被阻塞,也不需要关心线程何时被唤醒,一切都由阻塞队列自动帮我们完成。我们只需要关注具体的业务逻辑就可以了。
5.2 阻塞队列的分类https://blog.csdn.net/wcc178399/article/details/106663678
6、CompletableFuture异步编排应用场景:
电商项目中,获取商品详情通常业务比较复杂,还需要调用别的服务的接口,比较耗时。假如每个数据的获取时间如下图所示,如果不使用异步,用户需要5.5s后才能看到页面内容,显然是不合理的。如果使用异步,同时有6个线程同时获取这些数据,用户只需要1.5s即可看到!
CompletableFuture实现了Future接口,FutureTask也实现了Future接口
6.1 单任务异步 //自定义一个线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// CompletableFuture的使用
//1.无返回值的异步任务 runAsync()
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println("线程号为***" Thread.currentThread().getId());
int i = 5;
System.out.println("---------" i);
} service);
//2.有返回值异步任务 supplyAsync()
CompletableFuture<integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("线程号为***" Thread.currentThread().getId());
int i = 5;
System.out.println("---------" i);
return i;
} service).whenComplete((r e) -> {
// whenComplete第一个参数是结果,第二个参数是异常,他可以感知异常,无法返回默认数据
System.out.println("执行完毕,结果是---" r "异常是----" e);
}).exceptionally(u -> {
// exceptionally只有一个参数是异常类型,他可以感知异常,同时返回默认数据10
return 10;
// handler既可以感知异常,也可以返回默认数据,是whenComplete和exceptionally的结合
}).handle((r e) -> {
if (r != null) {
return r;
}
if (e != null) {
return 0;
}
return 0;
});
6.2 线程串行化
/**
* 3.线程串行化(把后边的线程和前边的串起来)
*/
//thenRunAsync()无返回值
CompletableFuture<Void> voidCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程号为***" Thread.currentThread().getId());
int i = 5;
System.out.println("---------" i);
return i;
} service).thenRunAsync(() -> {
System.out.println("thenRunAsync,不可接受传来的值,自己无返回值的串行化---");
} service);
//thenAccept(x)
CompletableFuture<Void> voidCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程号为***" Thread.currentThread().getId());
int i = 5;
System.out.println("---------" i);
return i;
} service).thenAccept((r) -> {
System.out.println("thenAccept可接受传来的值,自己无返回值的串行化---");
});
//thenApply(x)
CompletableFuture<Integer> voidCompletableFuture3 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程号为***" Thread.currentThread().getId());
int i = 5;
System.out.println("---------" i);
return i;
} service).thenApply((r) -> {
System.out.println("thenApply可接受传来的值,自己有返回值的串行化---");
return 10;
});
6.3 两任务组合
/**
* 异步,两任务组合 :两个任务都完成,第三个任务才开始执行
*/
//定义两个任务
//任务一
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> {
int i = 5;
System.out.println("任务一开始执行" i);
return i;
} service);
//任务二
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
int i = 10;
System.out.println("任务二开始执行" i);
return i;
} service);
//要求:任务一、二都完成后才执行任务三
// runAfterBothAsync:无传入值、无返回值
task1.runAfterBothAsync(task2 ()->{
System.out.println("任务三开始执行-runAfterBothAsync:无传入值、无返回值 ");
} service);
// thenAcceptBothAsync:有传入值、无返回值
task1.thenAcceptBothAsync(task2 (x y)->{
System.out.println("任务三开始执行-runAfterBothAsync:无传入值、无返回值 task1的结果是x task2的结果是y");
} service);
// thenCombineAsync:有传入值、有返回值
task1.thenCombineAsync(task2 (x y)->{
System.out.println("任务三开始执行-runAfterBothAsync:无传入值、无返回值 task1的结果是x task2的结果是y task3返回hello");
return "hello";
} service);
/**
* 异步,两任务组合 :两个任务都完成其中一个完成,第三个任务才开始执行
*/
/**
* runAfterEither 无传入值、无返回值
* acceptEither 有传入值、无返回值
* applyToEither 有传入值、有返回值
* 代码同上!
*/
6.4 多任务组合
/**
* 异步,多任务组合 :多个任务都完成,才进行下一步操作
* allOf() 等待所有任务完成
* anyOf() 只要有一个任务完成即可
* 注意:最后使用get()方法:阻塞式等待所有任务都做完,再进行下一步
*/
来源:blog.csdn.net/qq_45076180/article/details/107221610