java线程池分类图解(一文搞懂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数目
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com