线程池的getActiveCount()不准确问题
getActiveCount () 按照 javadocs 的说法是 “Returns the approximate number of threads that are actively executing tasks.” 也就是“返回正在执行任务的大致线程数”,请注意用词 approximate 。
查看一下源码:
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
该方法获取worker列表并计算被锁定的worker,返回计算结果。
当计数到达列表的末尾时,之前计算的一些worker可能已经完成了。(或者一些未使用的worker已经有了新任务。)
举个栗子:
public static void main(String[] args) throws Exception {
// 创建线程池
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("test-%d").build();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
11,
11,
65,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
namedThreadFactory);
int i = 0;
do{
while (threadPool.getActiveCount()>10){
try {
Thread.sleep(1 * 1000);
System.out.println("reach max pool size:"+threadPool.getPoolSize()+", wait 1 second...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
threadPool.execute(()->{
work();
});
i++;
}while (i<1000000);
}
private static void work(){
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" is over");
}
运行结果:
很奇怪,明明判断的是当活动线程数量大于10的时候,主线程就要等待一秒,理论上,threadPool.getActiveCount()是不可能大于11的,但是运行结果是threadPool.getActiveCount()一直在增加。
所以当线程多,或者线程不停的去执行任务时,这种计算得出来的结果并不是准确的,但这是多线程中固有的。举个栗子,假如线程池就是一个工厂,线程就是工人,你是工厂的boss,你想知道现在这个时刻有多少工人在干活,多少工人在休息,那你不能让一个工厂的所有工人都停下自己手头的工作,工厂停止运作然后去统计哪个在工作哪个在休息吧,所以当你的秘书给你统计的数据的时候,有些工人已经干完了手头的工作去休息了,有些工人或许有了新任务已经上岗干活了,时效性可能会导致结果的不准确。
解决办法
判断的时候主线程sleep一段时间:
do{
while (threadPool.getActiveCount()>10){
try {
Thread.sleep(1 * 1000);
System.out.println("reach max pool size:"+threadPool.getPoolSize()+", wait 1 second...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
threadPool.execute(()->{
work();
});
i++;
Thread.sleep(1); //当线程执行任务后,主线程休息1ms
}while (i<1000000);
再看运行结果
始终是11
如有解释不严谨,欢迎指出,不吝赐教