线程池的getActiveCount()不准确问题

线程池的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(
                5,
                20,
                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");
    }

运行结果:
线程池的getActiveCount()不准确问题

看到没,我明明判断的是当活动线程大于10的时候,主线程就等待一秒,理论上,threadPool.getActiveCount()是不可能大于11的,但是运行结果是threadPool.getActiveCount()一直在增加。

所以当线程多,或者线程不停的去执行任务时,这种计算得出来的结果并不是准确的,但这是多线程中固有的。举个栗子,假如线程池就是一个工厂,线程就是工人,你是工厂的boss,你想知道现在这个时刻有多少工人在干活,多少工人在休息,那你不能让一个工厂的所有工人都停下自己手头的工作,工厂停止运作然后去统计哪个在工作哪个在休息吧,所以当你的秘书给你统计的数据的时候,有些工人已经干完了手头的工作去休息了,有些工人有任务了需要上岗干活了,时效性可能会导致结果的不准确。

解决办法

判断的时候主线程slee一段时间

  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);

再看运行结果
线程池的getActiveCount()不准确问题

始终是11 。
如有解释不严谨,欢迎指出,不吝赐教