线程池技术实现及参数工作流程原理

一.什么是线程池

        线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。这里的线程就是我们前面学过的线程,这里的任务就是我们前面学过的实现了Runnable或Callable接口的实例对象。

为什么使用多线程

1.线程管理复杂 何时创建线程,何时销毁线程

2.任务管理复杂 任务什么时候接收,任务什么时候拒绝

二.线程池的实现及原理

  • Spring 中可以用 ThreadPoolTaskExecutor 配合 @Async 注解来实现(不太推荐)
  • Java 中,可以使用 JUC 并发包中的 ThreadPoolExecutor 来实现非常灵活的自定义线程池(推荐)。
线程池参数
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
  • corePoolSize(核心线程数 => 正式员工数量):正常情况下,我们系统应该能同时工作的线程数
  • maximumPoolSize(最大线程数 =>最多招多少人):极限情况下,我们线程池最多有多少个线程。
  • keepAliveTime(空闲线程存活时间):非核心线程在没有任务的情况下,过多久删除掉(理解为开除临时工)
  • TimeUnit unit(空闲线程存活时间的单位):分钟、秒
  • workQueue(工作队列):用于存放给线程执行的任务,存在队列的最大长度(一定要设置队列长度,不要设置成无限大)。
  • threadFactory(线程工厂):控制每个线程的生成、线程的属性(比如线程名)
  • RejectedExecutionHandler(拒绝策略):任务队列满的时候,我们采取什么策略,比如抛异常、不抛异常,自定义策略。
工作流程图

线程池工作机制
  1. 核心线程
    • 初始时,线程池有corePoolSize个核心线程(例如2个)。
    • 当提交新任务时,如果核心线程数未满,则直接由核心线程处理。
  2. 任务队列
    • 当核心线程都在忙碌时,新任务会被放入workQueue(阻塞队列)中等待处理。
    • workQueue的大小限制了能够等待的任务数量。
  3. 最大线程数
    • 如果workQueue已满,且当前线程数小于maximumPoolSize(例如4个),则线程池会创建新的临时线程来处理任务。
  4. 拒绝策略
    • workQueue已满,且线程数已达到maximumPoolSize时,再提交新任务会触发RejectedExecutionHandler定义的拒绝策略(如抛异常、丢弃任务等)。
  5. 空闲线程超时
    • 当线程池中的线程数量超过corePoolSize时,如果某个线程在keepAliveTime时间段内没有执行任务,那么该线程会被终止,以减少资源消耗。
举例有9个任务的情况

核心线程数为2  最大线程数为4  任务队列长度为4

核心线程是正式工,非核心线程是临时工
 

加入任务1,2    分配给核心线程1,2

加入任务3,此时核心线程数已满,看任务队列是否空闲,加入队列

陆续加入4,5,6到队列中

此时队列已满,任务7需要创建线程a,处理

任务8创建线程b处理

当有任务9时,此时最大线程数已满,无法创建线程,拒绝执行

如何确定线程池参数?

根据实际情况(实际业务场景 和 系统资源)来调整测试,不断优化参数。

比如:现有条件 AI 并发只允许 4 个任务同时执行,允许 20 个任务排队。

以上需求可设置如下参数:

  • corePoolSize(核心线程数):正常情况设置为 4
  • maximumPoolSize(最大线程数):设置为极限情况,数量 >= 4
  • keepAliveTime(空闲线程存活时间):一般设置为秒级/分钟级
  • TimeUnit unit(空闲线程存活时间的单位):分钟、秒
  • workQueue(工作队列):结合实际情况,可以设置为 20( AI 允许 20 个任务排队)
  • RejectedExecutionHandler(拒绝策略):抛异常,标记数据库任务状态为 “任务满了,已拒绝”
任务的划分(I/O 或计算密集型)

CPU (计算)密集型:计算较多,比如音视频处理、图像处理、数学计算等,一般设置 corePoolSize 为 CPU 的核心数 + 1 ( N+1 )。

I/O 密集型:吃带宽/内存/硬盘的读写资源,corePoolSize 可以设置大一点,通常经验值为 2N(N 为核心数),但建议以 I/O 能力为主。

优点:合理设置核心数能够让线程最大化利用 CPU,不至于频繁切换线程。

三.线程池示例代码

@Configuration
//创建线程池配置类
public class ThreadPoolExecutorConfig {
    @Bean //方法返回值对象加入容器里面
    public ThreadPoolExecutor generate(){
        //新建一个线程工厂
        ThreadFactory threadFactory=new ThreadFactory() {
            int count=1;//初始线程数
            @Override//重写线程创建方法
            //@NotNull保证参数r不为空
            public Thread newThread(@NotNull Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("线程"+count);//设置线程名字为线程数
                count++;
                return thread;//返回线程
            }
        };//创建一个线程池对象 指定各个参数//任务队列是阻塞队列//自定义线程工厂创建线程
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 100, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(4), threadFactory);
    return threadPoolExecutor;//返回线程池对象
    }
}
@Slf4j
@RestController
@Controller
@RequestMapping("/queue")
public class QueueController {
    @Autowired
    ThreadPoolExecutor threadPoolExecutor;
    @GetMapping("/add")
        public void add(String name){
        //CompletableFuture.runAsync()方法是用来异步地执行一个无返回值的Runnable任务
        CompletableFuture.runAsync(()->{
            log.info("任务执行中"+name+"执行者"+Thread.currentThread().getName());
            try {
                Thread.sleep(600000);//模拟长时间占用
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //异步任务在threadPoolExecutor里面执行
        },threadPoolExecutor);
        }

        @PostMapping("/get")
    public String get(){
            HashMap<String, Object> map = new HashMap<>();
            //获取任务总数
            long tasktotal=threadPoolExecutor.getTaskCount();
            //获取已经完成任务数
            long completedTaskCount = threadPoolExecutor.getCompletedTaskCount();
            //获取存活时间
            int activeCount = threadPoolExecutor.getActiveCount();
            //获取核心线程数
            int corePoolSize = threadPoolExecutor.getCorePoolSize();
            //获取最大线程数
            int maximumPoolSize = threadPoolExecutor.getMaximumPoolSize();
            //获取队列长度
            int size = threadPoolExecutor.getQueue().size();
            map.put("任务总数",tasktotal);
            map.put("已经完成任务数",completedTaskCount);
            map.put("存活时间",activeCount);
            map.put("核心线程数",corePoolSize);
            map.put("最大线程数",maximumPoolSize);
            map.put("队列长度",size);
            return JSONUtil.toJsonStr(map);

        }

}

 

  • 21
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河清风悠

你的鼓励就是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值