ThreadPoolExecutor获取当前工作线程数量

通过链接以下链接得知,分为高低位对应

  1. workerCount: 当前的工作线程数量,低位
  2. runState:线程池的状态,高位

https://www.jianshu.com/p/9a200a89bd64

源码如下

// ctl 变量是 int 类型,对应比特位是32位,按照高低位对运行状态和线程总数分别进行存储
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程总数用到的 int 类型总位数
private static final int COUNT_BITS = Integer.SIZE - 3;
// 最大线程总数,即 2^29-1=536,870,911,5亿多
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits

// 运行状态 runState,通过 runStateOf() 获取到对应的变量值

// RUNNING 对应 -536870912
private static final int RUNNING    = -1 << COUNT_BITS;
// SHUTDOWN 对应 0
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// STOP 对应 536870912
private static final int STOP       =  1 << COUNT_BITS;
// TIDYING 对应 1073741824
private static final int TIDYING    =  2 << COUNT_BITS;
// TERMINATED 对应 1610612736
private static final int TERMINATED =  3 << COUNT_BITS;

其中,线程池运行状态值通过位移计算得出

具体值如下

状态名状态值
RUNNING-536870912
SHUTDOWN0
STOP536870912
TIDYING1073741824
TERMINATED1610612736

通过源码注释得知,CAPACITY 的值为 2^29-1,即 536870911,五亿多。

// 获取运行状态 runState,CAPACITY 取反和 ctl 按位与
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 获取线程数量 workerCount,CAPACITY 和 ctl 按位与
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 运行状态和线程数量取或,用于设置运行状态
private static int ctlOf(int rs, int wc) { return rs | wc; }

workerCountOf 的计算逻辑

其中 CAPACITY 的值为固定值,将 ctl 变量的值与 CAPACITY 按位与,由于用于总数计算的数据位只有29位,按位与只返回都为1的数据,综合下来返回实际的 worker 总数。

runStateOf 的计算逻辑

将 CAPACITY 的值取反,则实际值为 0,将对应的值与 ctl 的值按位与,由于数据只返回都为1的数据且状态为高位,即只返回高位的状态数据。


   public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

从 execute 中得知,线程创建最终是通过 addWorker() 创建了 Worker 对象,继承了 aqs,实现了 

Runnable 接口。

如果线程数量小于核心线程总数,添加到核心线程中

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

通过 compareAndIncrementWorkerCount() 实现了对 ctl 变量的累加

    /**
     * Attempts to CAS-increment the workerCount field of ctl.
     */
    private boolean compareAndIncrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect + 1);
    }

由 addWorker() 代码得出,有两种情况不处理线程添加

有两种情况

1、如果线程数 workerCount 大于线程最大值,不处理

2、分两种情况

当前线程为核心线程,取核心线程数量

当前线程为非核心线程,取非核心线程数量

workerCount 大于等于线程数量,不处理,即 workerCount 小于线程数量才处理

即,工作线程数量不会大于最大线程池的数量。

满足处理线程的要求将 ctl 中 workerCount 自增1

到这里,任何提交的线程任务最终都是以 Worker 的形式来执行。

    /**
     * Returns the approximate number of threads that are actively
     * executing tasks.
     *
     * @return the number of threads
     */
    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 的数量。

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

在执行任务的时候会加锁,为了线程池中断。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread2 {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        int maximumPoolSize = corePoolSize << 1;
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 1, TimeUnit.SECONDS, workQueue);
        for (int i = 1;i <= 1000; i++) {
            executor.execute(new Thread());
            System.out.println(executor);
        }
    }
}

执行结果

java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 1]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 2, active threads = 1, queued tasks = 0, completed tasks = 1]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 3, active threads = 1, queued tasks = 0, completed tasks = 1]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 4, active threads = 1, queued tasks = 0, completed tasks = 3]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 5, active threads = 2, queued tasks = 0, completed tasks = 3]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 6, active threads = 2, queued tasks = 0, completed tasks = 4]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 7, active threads = 3, queued tasks = 0, completed tasks = 4]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 8, active threads = 4, queued tasks = 0, completed tasks = 4]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 9, active threads = 3, queued tasks = 0, completed tasks = 6]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 10, active threads = 3, queued tasks = 0, completed tasks = 7]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 11, active threads = 2, queued tasks = 0, completed tasks = 9]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 12, active threads = 2, queued tasks = 0, completed tasks = 10]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 13, active threads = 1, queued tasks = 0, completed tasks = 12]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 14, active threads = 1, queued tasks = 0, completed tasks = 13]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 15, active threads = 2, queued tasks = 0, completed tasks = 13]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 2, queued tasks = 0, completed tasks = 14]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 2, queued tasks = 1, completed tasks = 14]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 1, queued tasks = 0, completed tasks = 17]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 1, completed tasks = 18]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 1, completed tasks = 19]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 2, completed tasks = 19]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 3, completed tasks = 19]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 1, completed tasks = 22]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 24]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 1, completed tasks = 24]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 25]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 26]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 27]
java.util.concurrent.ThreadPoolExecutor@443b7951[Running, pool size = 16, active threads = 0, queued tasks = 0, completed tasks = 28]

...省略

执行结果参数含义如下

pool size
线程池中所有 Worker 线程的数量

active threads
正在执行的 Worker 数量

queued tasks
队列中的任务数量

completed tasks
已经完成任务数量

其中,toString() 中 active threads 对应的变量 nactive 的值和 getActiveCount() 逻辑一致,即通过 getActiveCount() 可以获取当期活跃的工作线程。任务在执行的时候会加锁,通过锁的状态可以判断当前任务是否活跃状态。

工作线程保存在 workers 中

/**
     * Set containing all worker threads in pool. Accessed only when
     * holding mainLock.
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

参考链接

https://blog.csdn.net/leimeng123/article/details/120989117

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值