Java基础教程:多线程基础——线程池
线程池
《阿里巴巴Java开发手册》有如下一则:
说明里介绍的很清楚,总结来说是这样的:
- 线程的创建和销毁是耗时较长、耗系统资源较多的操作。
- 将线程放到线程池中,方便管理,且提高线程的复用性,即一个线程可以分配给多个任务使用。
线程池原理
线程池状态及数量
线程池运行的状态,并不是用户显式设置的,而是伴随着线程池的运行,由内部来维护。线程池内部使用一个变量维护两个值:运行状态(runState)和线程数量 (workerCount)。在具体实现中,线程池将运行状态(runState)、线程数量 (workerCount)两个关键参数的维护放在了一起,如下代码所示:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //运行状态 & 线程数量
private static final int COUNT_BITS = Integer.SIZE - 3; private static final int RUNNING = -1 << COUNT_BITS;
...
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程状态分为五种:
线程池的生命周期:
任务执行机制
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
- 如果正在运行的线程少于corePoolSize线程,请尝试使用给定任务作为其第一个任务来启动新线程。 对addWorker的调用原子地检查runState和workerCount,从而通过返回false来防止在不应该添加线程的情况下发出错误警报。
- 如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为现有线程自上次检查后就已死亡)或自进入此方法以来该池已关闭。 因此,我们重新检查状态,并在必要时回滚排队,如果已停止,或者在没有线程的情况下启动新线程。
- 如果我们无法将任务排队,则尝试添加一个新线程。 如果失败,则表明我们已关闭或已饱和,因此拒绝该任务。
任务缓存
线程池的本质是对任务和线程的管理,阻塞队列负责缓存任务,工作线程从队列中获取任务以便执行。
说明:阻塞队列(BlockingQueue),即在普通队列的基础上实现以下两个附加操作
- 当队列满时,队列会阻塞插入元素的线程,直到队列不满。
- 当队列空时,队列会阻塞获取元素的线程,知道队列不空。