Java线程池种类及关键参数
在Java编码的过程中,我们经常会创建⼀个线程来提⾼程序的执⾏效率,虽然这样实现起来很⽅便,但是会有⼀个问题:如果并发的线程数多,并且每个线程都是执⾏⼀个时间很短的任务就结束了,这样会造成频繁的创建和销毁线程从⽽导致降低系统的效率。那么问题来了,有没有办法可⽤复⽤创建好的线程呢,也就是线程执⾏完⼀个任务后,不被销毁,继续执⾏其他的任务?
在Java可以通过线程池来实现这样的效果。下⾯从三个⽅⾯和⼤家⼀起来探讨⼀下Java线程池相关的内容:
1. Java中的ThreadPoolExecutor类
2. Java中4种线程池的使⽤
3. Java线程池常⽤参数如何设置。
⼀、Java中的ThreadPoolExecutor类
A.ThreadPoolExecutor的重要参数
核⼼线程会⼀直存活,及时没有任务需要执⾏。
当线程数⼩于核⼼线程数时,即使有线程空闲,线程池也会优先创建新线程处理。
设置allowCoreThreadTimeout=true(默认false)时,核⼼线程会超时关闭。
2.queueCapacity:任务队列容量(阻塞队列)
当核⼼线程数达到最⼤时,新任务会放在队列中排队等待执⾏。
3.maxPoolSize:最⼤线程数
当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务。java线程池创建的四种
当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务⽽抛出异常。
4.keepAliveTime:线程空闲时间
当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize。
如果allowCoreThreadTimeout=true,则会直到线程数量=0。
5.allowCoreThreadTimeout:允许核⼼线程超时
两种情况会拒绝处理任务:(1)当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务。(2)当线程池被调⽤shutdown()后,会等待线程池⾥的任务执⾏完毕,再shutdown。如果在调⽤shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务。线程池会调⽤rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常。
ThreadPoolExecutor类有⼏个内部实现类来处理这类情况:(1)AbortPolicy 丢弃任务,抛运⾏时异常。(2)CallerRunsPolicy 执⾏任务。(3)DiscardPolicy 忽视,什么都不会发⽣。(4)DiscardOldestPolicy 从队列中踢出最先进⼊队列(最后⼀个执⾏)的任务。实现RejectedExecutionHandler接⼝,也可⾃定义处理器。
B.ThreadPoolExecutor执⾏过程
1.当线程数⼩于核⼼线程数时,创建线程。
2.当线程数⼤于等于核⼼线程数,且任务队列未满时,将任务放⼊任务队列。
3.当线程数⼤于等于核⼼线程数,且任务队列已满。(1)若线程数⼩于最⼤线程数,创建线程。(2)若线程数等于最⼤线程数,抛出异常,拒绝任务。
⼆、Java中4种线程池
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。newFixedThreadPool 创建⼀个定长线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建⼀个定长线程池,⽀持定时及周期性任务执⾏。
newSingleThreadExecutor 创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执⾏。
三、Java线程池参数如何设置更合理
1.线程池的默认值
corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExcutionHandler=AbortPolicy()
2.如何来设置
a.需要⼏个数据来计算
tasks:每秒的任务数,假设为500~1000
taskCost:每个任务需要花费的时间,假设为0.1s
responseTime:系统允许的最⼤响应时间,假设为2s
b.计算过程
-
-corePoolSize=每秒需要的线程数?
threadCount=tasks/(1/taskCost)=tasks*taskCost=(500~1000)*0.1=50~100个线程。corePoolSize的个数应该⼤于等于50。根据8020原则,如果每秒80%的时间执⾏200个任务,那么corePoolSize设置为80即可。
--queueCapacity=(coreSizePool/taskCost)*responseTime
计算可得queueCapacity=(80/0.1)*2。意思是队列⾥的线程可以等待2秒,超过了就需要开新的线程来执⾏,千万不能设置为
Integer.MAX_VALUE,这样队列会很⼤,线程数只会保持在corePoolSize⼤⼩,当任务陡增时,不会开新的线程来执⾏,响应时间也会陡增。
--maxPoolSize=(max(tasks)-queueCapacity)/(1/taskCost)
计算可能maxPoolSize=(1000-80)/10=92,(最⼤任务数-队列容量)/每个线程每秒处理的任务数=最⼤线程数
--rejectedExecutionHandler:根据具体情况来决定,任务不重要可以丢弃,也可采⽤排队等策略
--keepAliveTime和allowCoreThreadTimeout通常采⽤默认值就可以
c.上⾯的计算都是理想的情况,在实际⽣产中,还要根据机器的性能,通横向扩展或者升级机器硬件来处理⾼并发产⽣的任务数
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论