网站首页 > java教程 正文
线程池详解
带着问题看源码:
1. 使用线程池有什么好处和作用?
2. 怎么创建线程池?
3. 线程池原理?
4. 线程池是如何复用线程的?
5. 线程池如何合理的配置?
线程是系统稀缺资源,如果不加限制的创建,不仅会消耗系统资源,严重的还会影响系统性能。所以希望有个统一的地方统一对线程的分配,调优和监控,这就是线程池。
使用线程池带来的好处:
1. 降低消耗,重复利用已创建好的线程,降低线程创建和销毁造成的消耗;
2. 提高响应速度,当任务到达时,任务可以不用创建线程就可以执行;
3. 提高线程的可管理性。
作用:为突然大量暴发的执行时间短的线程设计的,用几个固定的复用线程去为大量的操作服务。而不用大量频繁地创建销毁线程而浪费系统资源。
线程池的创建
JDK提供了Executors工具类,里面封装好了四种线程池的创建。
newCachedThreadPool:创建一个可根据需要创建线程的缓存线程池,可有线程可用时将重新使用以前的线程,否则将新一个线程并添加到线程池里。当线程空闲时间60S则终止并从缓存里删除。这样即使长时间保持空间也不会浪费资源。
newFixedThreadPool :创建一个固定长度的线程池。可控制最大的并发量,超出的线程则在队列里等待。
newScheduledThreadPool :创建一个定时任务线程池,可在给定的延迟时间或定期执行。
newSingleThreadExecutor:创建一个单线程的线程池,用唯一的一个线程来执行,可保证任务按顺序执行。
原理分析
线程池里的几个核心概念:
1. corePoolSize:核心线程数
2. maximumPoolSize:线程池最大线程数
3. keepAliveTime:线程没有执行任务的存活时间
4. workQueue:工作队列(阻塞队列BlockingQueue)
当一个任务到达时,线程池处理流程:
a) 判断工作线程数 < 核心线程数,如果小于则新建一个线程来执行任务;否则进入下一判断;
b) 工作队列未满时,则将任务加入队列;
c) 如果工作队列满了,判断工作线程数是否小于线程池的最大线程数,小于则新建一个线程来直接执行任务,大于则交由拒绝策略来执行此任务。
当向线程池添加执行任务时,调用
ThreadPoolExecutor.execute(Runnable command)方法
核心方法:addWorker(Runnable command,Boolean core)方法功能就是新建一个任务并执行或加入到队列里。
Worker是ThreadPoolExecutor的一个内部类,对执行任务的封装。
构造函数里将当前要执行的任务设给自己的变量。
线程池运行这个线程的时候其实就是执行Worker的run()方法
在runWorker()方法里对真正要执行的任务调用。
线程池复用线程也在这个方法里, runWorker ()里有很重要的一句话:
while (task != null || (task = getTask()) != null){}
task = getTask();当没有指定执行任务时,从工作队列里获取任务,在当前线程里循环执行完所有任务,这样就达到了复用线程的目的。
那什么时候worker里的任务会为空呢?
Execute()方法里
if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false);}
workerCountOf(recheck) == 0时会入addWorker()加入一个空的任务。
线程池配置
任何的架构或资源分配都需根据业务需求,想合理的配置线程池就必须分析任务特性,可以从以下几个角度分析:
1. 任务性质:CPU密集型任务,计算密集型任务,I/O密集型任务和混合型任务。
2. 任务的优先级:高中低。
3. 任务的执行时间:长中短。
4. 任务的依赖性:是否依赖系统的其他资源,如数据库连接。
任务性质不同就可以用不同规模的线程池来处理,CPU密集型任务需配置尽可能少的线程数,如CPU核数+1。这种类型的任务如果开太多线程处理会影响系统性能。
对于计算密集型的任务,在有N 个处理器的系统上,当线程池的大小为 N+1 时,能实现 CPU 的最优利用率。(即使当计算密集型的线程 偶尔由于页缺失故障或者其他原因暂停时,这个"额外" 的线程也能确保CPU 的时装周期不会被浪费。)对于 I/O 操作或其他 阻塞任务,由于线程并不会一直执行,因此线程池的规模应该更大。
一般计算公式:
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
猜你喜欢
- 2025-07-09 你真的会用 Java 中的线程池吗?多个企业级线程池工具类封装实践
- 2025-07-09 线程池的实现原理、优点与风险、以及四种线程池实现
- 2025-07-09 Java线程池ThreadPoolExecutor实现原理剖析
- 2025-07-09 深入分析线程池的实现原理(线程池是干嘛的)
- 2025-07-09 Java线程池的工作原理(java线程池的实现原理)
你 发表评论:
欢迎- 最近发表
-
- 你真的会用 Java 中的线程池吗?多个企业级线程池工具类封装实践
- 线程池的实现原理、优点与风险、以及四种线程池实现
- Java线程池ThreadPoolExecutor实现原理剖析
- 深入分析线程池的实现原理(线程池是干嘛的)
- 一文搞懂JAVA线程池工作原理(java线程池的工作流程)
- Java线程池的工作原理(java线程池的实现原理)
- 5分钟读懂C#中TcpClient、TcpListener和Socket三个类的角色
- JVM对象的创建过程(jvm运行过程中创建的对象一般存放在方法区)
- 对象组成与Java内存模型JMM分析(java对象在内存中存储的结构)
- JVM对象内存分配详细过程(栈上分配->TLAB->老年代->Eden区)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)