线程池

JDK创建线程池的方式

Executors.newFixedThreadPool(int num):创建固定大小的线程池。用于执行长期的任务。
Executors.newSingleThreadPool():创建单个线程的线程池。用于一个任务一个任务执行的场景。
Executors.newCacheThreadPool():创建采用一定调度机制的线程池,不确定线程数目。用于执行负载较轻的服务器。

它们的底层实现实际上都是调用了ThreadPoolExecutor来创建线程池,只是传入的参数不同。其中有一个参数是阻塞队列,FixedThreadPool和SingleThreadPool用的是LinkedBlockingQueue,而CacheThreadPool用的是SynchronousQueue。

线程池参数

corePoolSize:线程池中的常驻核心线程数。
maximumPoolSize:线程池能容纳同时执行的最大线程数。
workQueue:任务(阻塞)队列,指的是被提交但尚未执行的任务。
threadFactory:创建工作线程的工厂,一般用默认即可。
handler:拒绝策略,表示当任务队列满了并且工作线程数大于等于线程池能容纳同时执行的最大线程数(maximumPoolSize)。
keepAliveTime:指的是多余空闲线程的存活时间。也就是说当前线程池中的线程数量超过corePoolSize,当空闲时间达到keepAliveTime时,多余的空闲线程会被销毁直到只剩下corePoolSize个线程为止。
unit:指的是keepAliveTime的单位。

线程池的工作原理

线程池的工作原理就是,当任务进来的时候,先判断核心线程是否处于空闲状态,如果有核心线程处于空闲状态就让核心线程执行任务,如果核心线程都处于工作状态,就判断任务队列是否有位置存放该任务。如果任务队列有位置,就把任务放在任务队列中等待执行,如果任务队列中没有位置,就判断线程数量是否超过最大可容纳线程数,如果没有超过,就创建非核心线程执行任务,如果超过了就调用handler执行拒绝策略。

线程池的拒绝策略

启动时机:任务队列已满+线程池中线程数量达到maximumpoolsize。

策略:
1.Abortpolicy:直接抛出RejectedExecutionException异常,阻止系统继续运行。默认使用这种策略。当 任务数目>(线程池能容纳最大线程数+任务队列大小) 时,会抛此异常。

2.CallerRunsPolicy:这种策略既不会抛弃任务也不会抛出异常,而是让调用者运行一种调节机制,将某些任务回退给调用者,降低新任务流量。

3.DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加到队列中再次尝试提交任务。

4.DiscardPolicy:直接丢弃任务,不做任何处理。

实际中线程池如何使用

在生产中,必须通过线程池去创建线程,不能自己new一个线程,这样做是为了减少创建线程的开销。同时,不能使用JDK的Executors创建线程,因为这些线程池中的参数-阻塞队列linkedblockingqueue其默认大小为INTEGER_MAXVALUE可能会导致创建太多的线程而出现OOM。所以应该通过ThreadPoolExecutor的方式手动创建线程池。

我们可以通过自定义ThreadPoolExecutor中的参数来自定义线程池,给linkedblockingqueue设定一个大小而不再是MAXVALUE。

如何配置线程池参数:
首先要运行Runtime.getRuntime().availableProcessors() 来获知服务器的CPU数量;
如果任务是CPU密集型的(需要大量计算,而无阻塞),那应该配少一点线程数量(减少CPU切换开销),一般公式:CUP核数+1个线程 。

如果是IO密集型的,大部分线程都阻塞,因此要配置多一些线程。如CPU*2
还有参考公式:CPU核数/(1-阻塞系数) 阻塞系数在0.8~0.9之间

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值