java的线程池有几种 java线程的创建方式( 五 )


Worker执行任务的模型如下图所示:

java的线程池有几种 java线程的创建方式


图7 Worker执行任务
线程池需要管理线程的生命周期 , 需要在线程长时间不运行的时候进行回收 。线程池使用一张Hash表去持有线程的引用 , 这样可以通过添加引用、移除引用这样的操作来控制线程的生命周期 。这个时候重要的就是如何判断线程是否在运行 。
Worker是通过继承AQS , 使用AQS来实现独占锁这个功能 。没有使用可重入锁ReentrantLock , 而是使用AQS , 为的就是实现不可重入的特性去反应线程现在的执行状态 。
  1. lock方法一旦获取了独占锁 , 表示当前线程正在执行任务中 。
  2. 如果正在执行任务 , 则不应该中断线程 。
  3. 如果该线程现在不是独占锁的状态 , 也就是空闲的状态 , 说明它没有在处理任务 , 这时可以对该线程进行中断 。
  4. 线程池在执行shutdown方法或tryTerminate方法时会调用interruptIdleWorkers方法来中断空闲的线程 , interruptIdleWorkers方法会使用tryLock方法来判断线程池中的线程是否是空闲状态;如果线程是空闲状态则可以安全回收 。
在线程回收过程中就使用到了这种特性 , 回收过程如下图所示:
java的线程池有几种 java线程的创建方式


图8 线程池回收过程
2.4.2 Worker线程增加
增加线程是通过线程池中的addWorker方法 , 该方法的功能就是增加一个线程 , 该方法不考虑线程池是在哪个阶段增加的该线程 , 这个分配线程的策略是在上个步骤完成的 , 该步骤仅仅完成增加线程 , 并使它运行 , 最后返回是否成功这个结果 。addWorker方法有两个参数:firstTask、core 。firstTask参数用于指定新增的线程执行的第一个任务 , 该参数可以为空;core参数为true表示在新增线程时会判断当前活动线程数是否少于corePoolSize , false表示新增线程前需要判断当前活动线程数是否少于maximumPoolSize , 其执行流程如下图所示:
java的线程池有几种 java线程的创建方式


图9 申请线程执行流程图
2.4.3 Worker线程回收
线程池中线程的销毁依赖JVM自动的回收 , 线程池做的工作是根据当前线程池的状态维护一定数量的线程引用 , 防止这部分线程被JVM回收 , 当线程池决定哪些线程需要回收时 , 只需要将其引用消除即可 。Worker被创建出来后 , 就会不断地进行轮询 , 然后获取任务去执行 , 核心线程可以无限等待获取任务 , 非核心线程要限时获取任务 。当Worker无法获取到任务 , 也就是获取的任务为空时 , 循环会结束 , Worker会主动消除自身在线程池内的引用 。
try{while(task!=null||(task=getTask())!=null){//执行任务}}finally{processWorkerExit(w,completedAbruptly);//获取不到任务时 , 主动回收自己}线程回收的工作是在processWorkerExit方法完成的 。
java的线程池有几种 java线程的创建方式


图10 线程销毁流程
事实上 , 在这个方法中 , 将线程引用移出线程池就已经结束了线程销毁的部分 。但由于引起线程销毁的可能性有很多 , 线程池还要判断是什么引发了这次销毁 , 是否要改变线程池的现阶段状态 , 是否要根据新状态 , 重新分配线程 。

推荐阅读