今天跟别人讨论了线程池的核心线程会不会销毁的问题
先上代码
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(4,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(20));
//pool.allowCoreThreadTimeOut(true);
int a = 10;
for (int i = 1; i <= a; i++) {
int j = i;
pool.submit(new Runnable() {
@Override
public void run() {
if(j == 10){
throw new RuntimeException();
}
//获取线程名称
Thread thread = Thread.currentThread();
String name = thread.getName();
//输出
int activeCount = pool.getActiveCount();
System.out.println("任务:"+j+"-----,线程名称:"+name+"-----活跃线程数:"+activeCount+"-----线程数"+pool.getPoolSize());
}
});
}
Thread.sleep(6000);
System.out.println("线程数"+pool.getPoolSize()+"-----,活跃线程数"+pool.getActiveCount());
}
结果:活跃线程数为0,池内线程数量为核心线程数(这里要注意getPoolSize和getActiveCount不要混为一谈!!!线程不活跃了但是还是在池子里!!!只是空闲了,另外看评论区可能有一些同学会误解,这里是在线程池完全空闲时,用getPoolSize的数量与corePoolSize数量一致来说明线程池的确创建了4个核心线程池,而不是说getPoolSize就是核心线程数)如果对线程池原理不够理解,点这里
大家可能看到我注释了一行代码,那么就看看不注释掉的运行结果
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(4,10,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(20));
pool.allowCoreThreadTimeOut(true);
int a = 10;
for (int i = 1; i <= a; i++) {
int j = i;
pool.submit(new Runnable() {
@Override
public void run() {
if(j == 10){
throw new RuntimeException();
}
//获取线程名称
Thread thread = Thread.currentThread();
String name = thread.getName();
//输出
int activeCount = pool.getActiveCount();
System.out.println("任务:"+j+"-----,线程名称:"+name+"-----活跃线程数:"+activeCount+"-----线程数"+pool.getPoolSize());
}
});
}
Thread.sleep(6000);//一定要大于KeepAliveTime的值
System.out.println("线程数"+pool.getPoolSize()+"-----,活跃线程数"+pool.getActiveCount());
}
结果:核心线程被销毁了,线程数为0:
corePoolSize:返回核心线程数,类似于配置,不会随着核心线程被销毁而改变,所以我们用getPoolSize来进行验证
/**
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*/
private volatile int corePoolSize;
allowCoreThreadTimeOut:设置控制核心线程是否可以超时并终止的策略,如果在保活时间内没有任务到达,则在新任务到达时根据需要替换。当为 false 时,核心线程永远不会由于缺少传入任务而终止。如果为真,则适用于非核心线程的相同保活策略也适用于核心线程。为避免持续的线程替换,设置 true 时保持活动时间必须大于零。通常应该在主动使用池之前调用此方法。
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
private volatile boolean allowCoreThreadTimeOut;
getPoolSize:返回线程池当前线程数
/**
* Returns the current number of threads in the pool.
*
* @return the number of threads
*/
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Remove rare and surprising possibility of
// isTerminated() && getPoolSize() > 0
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
源码:直接看runWorker的processWorkerExit
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//无论如何都会执行到这个方法
processWorkerExit(w, completedAbruptly);
}
}
看来重点在processWorkerExit方法
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
//allowCoreThreadTimeOut 默认false 即 min默认为corePoolSize
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//如果min为0但是工作队列不为空,则至少要创建一个新的worker
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
结论:当allowCoreThreadTimeOut手动设置为true或者执行的run方法抛出异常,核心线程都会被销毁,但是后者还是会创建新的线程称呼来,前者则销毁什么都不做,关键在于allowCoreThreadTimeOut为true则下面代码直接返回,不在执行addWorker方法
if (workerCountOf(c) >= min)
return; // replacement not needed