本系列主要深入解析Java并发框架的内容,这是第一部分的内容,分析java并发中有关线程池的相关内容。
线程池概况
减小新创建和回收线程的压力,线程数实现线程的复用。
线程池的创建
构造参数
corePoolSize 与 maxPoolSize: 前者是只要创建到了就不会减小,即使没有任务,但是maxPoolSize是在队列满了之后,可以灵活的增加新的线程,这个是线程池的上线。
keepAliveTime: 新增的非核心线程的最大存活时间,超过这个时间没有执行任务就会被回收。
workQueue: 1.直接队列 SynchronousQueue. 2. 无界 LinkedBlockingQueue 3. 有界 ArrayBlockingQueue
threadFactory:一般就是用默认的就可以Excutors.defaultThreadFactory()
线程的添加规则
线程池的调用逻辑
核心是ThreadPoolExecutor
类,这里源码值得一看。涉及到一些函数的可以自己定义自己合适的线程池,如beforeExcutor
等。
1 | // 线程池调度的核心代码 在ThreadPoolExecutor类中的execute方法 |
常用默认线程池
手动创建可以避免一些风险,并且需要和业务匹配。
以下是自动创建的线程池。
ExecutorService threadpool = Executors.nexFixedThreadPool(4)
固定数量ExecutorService threadpool = Executors.nexSingleThreadPool()
单一
以上两个都是LinkedBlockingQueue
ExecutorService threadpool = Executors.nexCachedThreadPool()
可无限创建,core = 0SynchronousQueue
ExecutorService threadpool = Executors.nexScheduledThreadPool(10)
可以延迟运行DelayedWorkQueue
线程数量的设计
CPU密集:线程数量为CPU的1-2倍
IO型:可以大于很多倍。线程数 = cpu*(1+等待时间/工作时间)
停止线程的方法
实例方法
shutdown()
:提交上去关闭的请求,但是主动权在线程池。更安全。可以用实例方法isShutdown()
判断。或者isTerminated()
判断,awaitTerminated()
延迟判断是不是结束了线程池。实例方法
shutdownNow
: 立刻结束。中断所有正在执行的线程,并且返回没有进行的任务。
拒绝任务的策略
- 拒绝时机:线程关闭后或者最大线程和工作队列容量已经饱和。
默认的四种拒绝策略:
线程池的状态
线程池的组成与实现原理
线程池的组成
线程池包括:管理器(创建和停止),工作线程,任务队列(BlockingQueue),任务接口(Task)
Executor家族
线程池继承与实现的关系:
辨析:
- Executor:是一个顶层接口,只有一个方法
Runnable()
。执行任务的。 - ExecutorServices:继承了Executor的接口,可以管理线程池,
shutdown()
等。 - Executors:这是一个工具类。
线程池如何复用
每一个线程池拿到任务以后不断检测有没有新的任务,然后执行run
。
使用线程池的注意事项:
- 防止任务堆积
- 避免线程过度增加
- 排查线程泄露:线程执行完毕,无法被回收。