线程池执行以及回收原理(二)
线程回收
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
我们在设置线程池的时候往往会设置keepAliveTime(最大存活时间),我们都知道如果超过这个存活时间,线程池会回收额外的线程达到核心线程数,
1、回收的原理是什么?
2、核心线程与非核心线程有什么区别吗?
3、非核心线程可以核心线程吗?
在线程池执行以及回收原理(一)主要讲述了线程在执行过程中的创建以及如何获取task任务,下面就是getTask()的任务
-
private Runnable getTask() {
-
boolean timedOut = false; // Did the last poll() time out?
-
-
for (;;) {
-
int c = ctl.get();
-
int rs = runStateOf(c);
-
-
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
-
decrementWorkerCount();
-
return null;
-
}
-
-
int wc = workerCountOf(c);
-
// 步骤1
-
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
-
-
// 步骤2
-
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
-
// 步骤2.1
-
if (compareAndDecrementWorkerCount(c))
-
return null;
-
continue;
-
}
-
-
try {
-
// 步骤3
-
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
-
if (r != null)
-
return r;
-
timedOut = true;
-
} catch (InterruptedException retry) {
-
timedOut = false;
-
}
-
}
-
}
在步骤3中: workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) keepAliveTime在这里使用,表示workQueue等待keepAliveTime的时长,若果没有获取到或者超时返回null值。
workQueue具体含义什么呢?从上一篇文章可以知道线程池执行以及回收原理(一),这是一个阻塞队列,当核心线程数 =< 当前线程数 < 最大线程数时,我们将任务封装放进一个阻塞队列,这就是那个阻塞队列;
整体我们就可以知道,
1、如果队列中没有任务的,步骤3获取的r参数为空,timeout就会设置成true
2、进行步骤1的判断,假设这个线程执行的时候wc > corePoolSize成立,则timed为true,步骤2中timed && timedOutweitrue,wc >1也为true,
3、进行步骤2.1的操作,使用cas进行ctl减1的操作,返回null值,此时线程等待系统的回收。
所有的线程都进行如此的操作直到wc > corePoolSize不再成立,ctl这个工作线程的数目等于corePoolSize,此时步骤1获取的timed为false,此时步骤2的判断不再成立,执行步骤3的操作,但是注意此时timed为false,执行三元运算符中的workQueue.take(),此操作是阻塞的,直到workQueue中可以获取到值才能继续运行。这也就是整体的线程池的回收直至存活数目等于核心线程数目
有个关键参数allowCoreThreadTimeOut,这个参数默认是false,如果设置成true,所有的线程都会回收。
这样我们就可以回答上面的问题2与问题3了。
核心线程与非核心线程有什么区别?非核心线程可以核心线程吗?他们两个没有什么区别,能否成为核心线程完全是随机的,主要就是看谁先能提前进入阻塞当中,谁就会成为最终留下来的核心线程
下图是线程池的原理示意图
https://www.cnblogs.com/semi-sub/p/13908099.html
回复 8888可以领取面试资料,感谢各位小伙伴的关注