线程池

线程

操作系统调度运算的最小单位,开发过程中可以通过实例线程执行任务,实现并发的效果

线程池作用

1、有效的通过约束实现降低线程创建和销毁的资源消耗
2、提高任务响应速度,无需等待线程创建
3、提供线程统一的管理、监控和调优

ThreadPoolExecutor线程池参数

参数作用
corePoolSize核心线程数量,线程池维护线程的最少数量
maximumPoolSize线程池维护线程的最大数量
keepAliveTime线程池除核心线程外的其他线程的最长空闲时间,超过该时间的空闲线程会被销毁
unitkeepAliveTime的单位,TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS
workQueue线程池所使用的任务缓冲队列
threadFactory线程工厂,用于创建线程,一般用默认的即可
handler线程池对拒绝任务的处理策略

拒绝策略handler

当线程池任务处理不过来的时候(什么时候认为处理不过来后面描述),可以通过handler指定的策略进行处理,ThreadPoolExecutor提供了四种策略:

拒绝策略类型处理方式
ThreadPoolExecutor.AbortPolicy丢弃任务并抛出RejectedExecutionException异常;也是默认的处理方式。
ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy丢弃队列队头的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy由调用“当前线程”处理该任务

可以通过实现RejectedExecutionHandler接口自定义处理方式。

阻塞队列类型

队列名称队列特征
ArrayBlockingQueue这是一个由数组实现的容量固定的有界阻塞队列.
SynchronousQueue没有容量,不能缓存数据;每个put必须等待一个take; offer()的时候如果没有另一个线程在poll()或者take()的话返回false。
LinkedBlockingQueue这是一个由单链表实现的默认无界的阻塞队列。LinkedBlockingQueue提供了一个可选有界的构造函数,而在未指明容量时,容量默认为Integer.MAX_VALUE。
PriorityBlockingQueue有序的阻塞队列,无界
DelayBlockingQueue每一个任务都可以设置一个延时时间,等待延时时间过了才能够被线程获取

阻塞队列基本操作如下

方法名作用
add增加一个元索; 如果队列已满,则抛出一个异常
remove移除并返回队列头部的元素; 如果队列为空,则抛出一个异常
element返回队列头部的元素; 如果队列为空,则抛出一个异常
offer添加一个元素并返回true; 如果队列已满,则返回false
poll移除并返回队列头部的元素; 如果队列为空,则返回null
peek返回队列头部的元素; 如果队列为空,则返回null
put添加一个元素; 如果队列满,则阻塞
take移除并返回队列头部的元素; 如果队列为空,则阻塞

线程池执行方法

  • Future submit(Callable c)
  • Future submit(Runnable r,Object o)
  • 该方法返回一个Future对象,可执行带返回值的线程;或者执行想随时可以取消的线程。

Future对象的get()(如果没有执行完任务,则阻塞当前线程)方法获取返回值。Future对象的cancel(true/false)取消任务,未开始或已完成返回false,参数表示是否中断执行中的线程

  • void execute(Runnable r) 没有返回值,只能接收实现Runnable的任务。
  • shutdown() 不接收新任务,会处理已添加任务
  • shutdownNow() 不接受新任务,不处理已添加任务,中断正在处理的任务

执行过程图如下

在这里插入图片描述
1、如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列。
2、如果此时线程池中的数量大于等于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务
3、如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
4、当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。
总结即:处理任务判断的优先级为 核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

注意:

  • 当workQueue使用的是无界限队列时,maximumPoolSize参数就变的无意义了,比如new LinkedBlockingQueue(),或者new ArrayBlockingQueue(Integer.MAX_VALUE);
  • 使用SynchronousQueue队列时由于该队列没有容量的特性,所以不会对任务进行排队,如果线程池中没有空闲线程,会立即创建一个新线程来接收这个任务。maximumPoolSize要设置大一点。
  • 核心线程和最大线程数量相等时keepAliveTime无作用.

默认的线程池

1) FixedThreadPool(固定大小线程池) 和 SingleThreadPool(单线程线程池):
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2) CachedThreadPool (缓冲区线程池)和 ScheduledThreadPool(定时线程池):
允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程,从而导致 OOM。

使用情景模拟

(1)高并发、任务执行时间短的业务,线程池核心线程数可以设置为CPU核数+1,减少线程上下文的切换
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的核心线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值