文章目录
- 一、七大元素解释
- 1.corePoolSize(核心线程数):
- 2.maximumPoolSize(最大线程数):
- 3.keepAliveTime(线程空闲时间):
- 4.unit(时间单位):
- 5.workQueue(任务队列):
- 6.threadFactory(线程工厂):
- 7.handler(拒绝策略):
- 二、CountDownLatch扩展
一、七大元素解释
创建 ThreadPoolExecutor 对象时,可以通过参数控制线程池的大小、任务队列、线程空闲时间等
1.corePoolSize(核心线程数):
表示线程池中保持的常驻核心线程数,即使线程处于空闲状态,也不会被回收。核心线程会一直存活,除非设置了 allowCoreThreadTimeOut 参数为 true,允许核心线程在一定时间内空闲时被回收。
2.maximumPoolSize(最大线程数):
表示线程池中允许的最大线程数。当线程池中的线程数达到这个值时,后续的任务会被放入任务队列中等待执行,或者执行拒绝策略,具体取决于任务队列和拒绝策略的配置。
3.keepAliveTime(线程空闲时间):
表示当线程池中的线程数大于核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。超过这个时间,多余的线程会被终止,直到线程数不超过核心线程数。
4.unit(时间单位):
表示线程空闲时间的单位,通常是秒、毫秒等。
5.workQueue(任务队列):
表示用于保存等待执行的任务的队列。线程池会根据核心线程数和任务队列来决定是否创建新的线程。常用的任务队列有 LinkedBlockingQueue、ArrayBlockingQueue、SynchronousQueue 等。
6.threadFactory(线程工厂):
表示创建新线程的工厂类,用于自定义线程的名称、优先级等属性。
7.handler(拒绝策略):
表示线程池无法执行新任务时的处理策略。当线程池的线程数达到最大线程数并且任务队列已满时,会触发拒绝策略。常用的拒绝策略有 ThreadPoolExecutor.AbortPolicy、ThreadPoolExecutor.DiscardPolicy、ThreadPoolExecutor.CallerRunsPolicy 等
package com.ccy.agriculture.test;
import java.util.concurrent.*;
/**
* 文件名称(File Name):
* 功能描述(Description):此模块的功能描述与大概流程说明
* 数据表(Tables):表名
*
* @Author wujiahao
* 日期(Create Date):2023/7/26
* 修改记录(Revision History):
*/
public class CustomThreadPool {
public static void main(String[] args) {
// 1. corePoolSize(核心线程数):5
// 表示线程池中保持的常驻核心线程数为 5,即使线程处于空闲状态,也不会被回收。
int corePoolSize = 5;
// 2. maximumPoolSize(最大线程数):10
// 表示线程池中允许的最大线程数为 10。当线程池中的线程数达到这个值时,
// 后续的任务会被放入任务队列中等待执行,或者执行拒绝策略。
int maximumPoolSize = 10;
// 3. keepAliveTime(线程空闲时间):60
// 表示当线程池中的线程数大于核心线程数时,多余的空闲线程在终止前等待新任务的最长时间为 60 秒。
// 超过这个时间,多余的线程会被终止,直到线程数不超过核心线程数。
long keepAliveTime = 60;
// 4. unit(时间单位):TimeUnit.SECONDS
// 表示线程空闲时间的单位为秒。
TimeUnit unit = TimeUnit.SECONDS;
// 5. workQueue(任务队列):LinkedBlockingQueue
// 表示用于保存等待执行的任务的队列为 LinkedBlockingQueue。
// LinkedBlockingQueue 是一个无界队列,可以保存无限数量的等待执行任务。
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
// 6. threadFactory(线程工厂):默认的线程工厂
// 不对线程工厂进行自定义,使用默认的线程工厂。
// 7. handler(拒绝策略):ThreadPoolExecutor.AbortPolicy
// 当线程池的线程数达到最大线程数并且任务队列已满时,采用默认的拒绝策略 AbortPolicy,
// 即抛出 RejectedExecutionException 异常,拒绝新的任务执行。
// 创建自定义线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
corePoolSize, // 核心线程数
maximumPoolSize, // 最大线程数
keepAliveTime, // 线程空闲时间
unit, // 时间单位
workQueue // 任务队列
);
// 提交任务给线程池执行
for (int i = 1; i <= 20; i++) {
final int taskNumber = i;
threadPool.execute(() -> {
System.out.println("Task " + taskNumber +
" is being executed by Thread " + Thread.currentThread().getName());
});
}
// 关闭线程池
threadPool.shutdown();
}
}
这里可以打印出每个任务在哪个线程执行,不需要一个一个地等待前面的任务完成才能开始执行,可以并行执行多个任务,从而更好地利用系统资源
让主线程在控制台打印,可以发现主线程和线程池里的线程并发执行任务
二、CountDownLatch扩展
现实中很多业务会让子线程完成所有任务后再执行主线程,比如海量Excel表导入,要先分表读取数据再导入,这时要控制主线程要在最后执行任务,于是Java引入了CountDownLatch对象。
CountDownLatch定义一个初始值,主线程调用await()方法阻塞线程,然后每当子线程执行任务时调用countDown()方法,每调用一次计数值减一,当计数值为0时就可以唤醒主线程。
countDownLatch.await(2000,TimeUnit.MILLISECONDS);
打个比方就是你去餐馆点了20个菜,餐馆有5个厨师帮你做菜,每做一道菜就在订单上划掉对应的菜(减一操作),当所有菜做好了就可以进行上菜这个主线程了(不要跟我杠什么可以边做菜边上菜,我这个餐馆就是要做完所有菜才能上菜)
await()也可以加参数,以保证主线程必须执行。下面这串代码表示不管子线程任务是否执行完,2000毫秒之后就执行主线程。我遇过子线程拒绝新任务的情况,这样主线程就不会执行了。
友情提示:以上为纯八股文🤡