让人思来想去的ThreadPool

简介: 一直以来被一个线程池中核心线程跟非核心线程有什么区别的问题困惑着自己,是时候直面恐惧了。

线程池的意义

避免线程过多创建产生的资源浪费,及性能瓶颈,控制资源总量,复用线程,加快响应速度,合理利用cpu和内存,便于管理,以及代码的维护更加整洁

适合场景

服务器端开发,tomcat就用到了线程池。

超过5个线程协作的方法,需要使用线程池。

注意事项

队列积压过多任务,导致内存溢出

线程数量太多导致内存溢出


线程池的参数

线程池的状态

running:接受新任务并处理排队任务

shutdown:不接受任务但是处理排队任务

stop:不接受新任务,也不处理排队任务,并中断正在进行的任务

tidying:所有任务都已终止,workerCount为0,并将运行terminate()钩子方法

terminate:terminate()方法运行完成

线程池核心参数

corePoolSize:核心线程数,当没有满足核心线程数时创建线程执行任务

maximumPoolSize:最大线程数,当任务队列满了,且线程数不满足最大线程数时创建线程执行任务

keepAliveTime:无任务时,线程存活时间,当达到该时间且没有任务时,该线程会被标记成可回收。

unit:时间单位

workQueue:任务队列,存放任务的

threadFactory:线程工厂,通过怎样的工厂类创建线程

handler:当不能工作时的拒绝策略,当达到最大线程数及队列满了的时候,触发拒绝机制,以及线程池关闭的时候

线程数

有关线程池中,线程数的设置;

计算密集型,corePoolSize = cpu 个数 + 1  = maximumPoolSize

IO密集型,则因为线程并不总是在工作,基于线程工作时间与等待时间求比+1 * cpu 的占用比例* cpu 的数量,随着等待时间与工作时间的比例,在一定区间内进行浮动。

如果是混合型的计算需求,那么就具体按照机器的性能,进行设置线程数。

源码中线程数量与线程池的状态用了一个AtomicInteger 进行存储,线程池的状态有5种,使用高3位进行表示,最大线程数其实不能超过61位能标识的最大数。

核心线程与非核心线程之区别

代码分析

开始创建时有些许差异,我们来看java.util.concurrent.ThreadPoolExecutor 的execute 方法:

publicvoidexecute(Runnablecommand) {
if (command==null)
thrownewNullPointerException();
intc=ctl.get();
if (workerCountOf(c) <corePoolSize) {
// 创建核心线程if (addWorker(command, true))
return;
c=ctl.get();
    }
if (isRunning(c) &&workQueue.offer(command)) {
intrecheck=ctl.get();
if (!isRunning(recheck) &&remove(command))
reject(command);
elseif (workerCountOf(recheck) ==0)
// 线程数扩容addWorker(null, false);
    }
elseif (!addWorker(command, false))
reject(command);
}

其实可以看到线程池初始化线程时addWorker 方法是传了firstTask 的,扩容线程时则传的是null,这可以是一个差异点,不过当线程池都创建好后,不再有差异,只会存活核心线程数量那么多的线程,达到超时时间的线程会被设置成可销毁状态,有代码为证:  

finalvoidrunWorker(Workerw) {
Threadwt=Thread.currentThread();
Runnabletask=w.firstTask;
w.firstTask=null;
w.unlock(); // allow interruptsbooleancompletedAbruptly=true;
try {
while (task!=null|| (task=getTask()) !=null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;// if not, ensure thread is not interrupted.  This// requires a recheck in second case to deal with// shutdownNow race while clearing interruptif ((runStateAtLeast(ctl.get(), STOP) ||                 (Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
task.run();
afterExecute(task, null);
                } catch (Throwableex) {
afterExecute(task, ex);
throwex;
                }
            } finally {
task=null;
w.completedTasks++;
w.unlock();
            }
        }
completedAbruptly=false;
    } finally {
processWorkerExit(w, completedAbruptly);
    }
}

我们可以从上面代码看到的是,当worker 在执行任务的时候,firstTask 被设置成了null,其实跟之后扩容的线程也就没太大区别了;

总结

总结下为什么扩容的线程不包含first task,其实是想让新建的线程在任务队列中获取任务进行执行;

那为什么有的线程初次创建时却携带first task 是因为线程池在创建时并没有创建线程,而是等任务来了以后才创建的线程,不得不佩服JDK 的创造者们啊。


总结的有些仓促,有机会重新整理下内容,大家加油!


相关文章
数据库系统工程师考点笔记
数据库系统工程师考点笔记
1372 0
|
Apache Java 数据库连接
Apache Doris 2.0.15 版本发布
Apache Doris 2.0.15 版本已于 2024 年 9 月 30 日正式与大家见面,该版本提交了 157 个改进项以及问题修复,进一步提升了系统的性能及稳定性,欢迎大家下载体验。
272 1
|
9月前
|
存储 安全 数据安全/隐私保护
STM32 Customer BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
本文介绍了基于STM32的Customer BootLoader刷新项目的第一部分:使用STM32CubeMX搭建UART串口通信工程。项目采用正点原子探索者v2开发板,通过USB串口与上位机通信,实现固件刷新功能。主要内容包括: 1. 硬件原理图介绍:详细描述了开发板的串口连接方式及电路图。 2. STM32CubeMX工程搭建:从创建新工程、配置系统时钟、USART串口设置到生成代码,一步步详细说明。 3. 代码编写:展示了如何使用HAL库实现串口接收和发送数据,并提供了main.c的完整代码。 4. 工程下载和调试:编译并下载工程到开发板,通过串口调试助手验证通信功能。
STM32 Customer BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
|
12月前
|
自然语言处理 小程序 IDE
只要几句话,通义灵码帮你创建专属健康管理小程序
数字时代的大潮中,编程不再高深莫测,而是每个人都可以尝试并享受的乐趣。今天,就让我们一起探索如何利用通义灵码的自然语言生成代码功能,轻松打造你的专属健康管理小程序,说不定在这个过程中,不管是身材管理,还是编程学习,都能让你离目标更近一步。
|
12月前
|
监控 小程序 前端开发
排队免单小程序开发源码案例
“排队免单小程序”旨在通过用户排队行为结合特定规则为用户提供免单或优惠机会,提升用户体验及商家流量。核心功能包括用户注册登录、排队管理、免单规则设置、支付与结算、商家管理和通知提醒等。技术上采用微信小程序开发框架,前后端分离架构,集成微信支付等服务,确保高效安全的数据处理与传输。项目开发过程涵盖需求分析、设计开发、集成测试和上线发布,后期注重数据监控、用户反馈和运营推广,以持续优化用户体验。
|
IDE Java 测试技术
通义灵码测评报告
通义灵码测评报告
710 1
|
Python
Tkinter学习笔记(一):完成文件选择和保存对话框
关于如何使用Python的Tkinter库来创建文件选择和保存对话框的教程。
337 2
|
Web App开发 安全 大数据
大数据问题排查系列-开启 kerberos 后无法访问 HIVESERVER2 等服务的 WEBUI
大数据问题排查系列-开启 kerberos 后无法访问 HIVESERVER2 等服务的 WEBUI
|
机器学习/深度学习 人工智能 算法
强化学习:实现自主决策的机器学习范 paradigm
强化学习作为实现自主决策的机器学习范 paradigm,在人工智能领域具有重要地位。通过与环境的交互学习,智能体能够逐步优化决策策略,从而在各种任务中表现出色。强化学习在游戏、机器人控制、自动驾驶等领域的应用案例充分证明了其潜力。未来,随着技术的进一步发展,强化学习将在更多领域带来创新和突破。
1044 1
|
存储 缓存 监控
启动选项和系统变量
启动选项和系统变量
259 0