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

CSDN博客 · · 443 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

线程池的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

如有解释不严谨,欢迎指出,不吝赐教

本文来自:CSDN博客

感谢作者:CSDN博客

查看原文:线程池的getActiveCount()不准确问题

443 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传