Supplement to JUC's thread pool problem

Question 1: When to turn on maximumPoolSize

In the previous blog, the understanding of the seven parameters of the thread pool of JUC , it was mentioned:

1. When the corePoolSize 核心数upper limit is reached, the new operation data at this time will be saved in the queue.
2, when 队列the memory was full time, will open maximumPoolSize - corePoolSizepart.

Insert picture description here

Question 2: Why wait until the queue is full before turning on maximumPoolSize

Before explaining this problem, we need to understand two concepts: 提交优先级and 执行优先级.

  • 提交优先级:

In 线程池,
1. The processing operation will be handed over corePoolSizeto the data processing first .
2. If it corePoolSizeis full, it will give priority to 队列temporary storage.

As follows:
Insert picture description here

  • 执行优先级:

1. Try to hand it over corefor data processing first .
2. If it is core 被占用, it will be handed over to the remaining processing window for processing.
3. If the maxprocessing window is all occupied, the data will be temporarily stored in the queue.

As shown below:
Insert picture description here
View source code description:

Any operation that gets an operation item from the thread pool is called execute(Runnable command).

Source part:
Insert picture description here

// 用来标记线程池状态(高3位),线程个数(低29位)
// 默认 RUNNING 状态,线程个数为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 用来获取线程个数
private static final int COUNT_BITS = Integer.SIZE - 3;
// 用于获取线程最大个数
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// 各项状态参数信息
// 正在运行
private static final int RUNNING    = -1 << COUNT_BITS;
// 已经关闭
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// 停止
private static final int STOP       =  1 << COUNT_BITS;
// 整理
private static final int TIDYING    =  2 << COUNT_BITS;
// 终止
private static final int TERMINATED =  3 << COUNT_BITS;

// Packing and unpacking ctl
private static int runStateOf(int c)     {
    
     return c & ~CAPACITY; }
private static int workerCountOf(int c)  {
    
     return c & CAPACITY; }
private static int ctlOf(int rs, int wc) {
    
     return rs | wc; }

public void execute(Runnable command) {
    
    
		// 判断 runnable 对象体是否存在
        if (command == null)
            throw new NullPointerException();
        // 这个 c 就是当前的线程池状态值 默认为 ctlOf(RUNNING, 0) 运行中且线程个数为0
        // ctl 记录runstate 和 workercount
        int c = ctl.get();
        // workerCountOf(c) 取出 低29 位数据值,即活动线程数
        // 如果活动线程数  小于 core(核心) 线程数
        // 则会新建线程,放置于池中,并将runnable任务加入该线程
        if (workerCountOf(c) < corePoolSize) {
    
    
        	// 如果 创建 “核心线程数据体” 成功  则直接退出
            if (addWorker(command, true))
                return;
            // 创建核心线程失败,重新获取 活动线程状态
            c = ctl.get();
        }
		// 将 重新获取到线程池的状态值,进行判断
        // 如果线程池的状态是 “正在运行”,并且将这个Runnable任务放入队列成功!
        if (isRunning(c) && workQueue.offer(command)) {
    
    
        	// 重新获取 线程状态值
            int recheck = ctl.get();
            // 这里是安全校验
            // 如果监测到线程池为“非运行状态”,则需要将上面workQueue.offer(command)成功的数据移除
            if (! isRunning(recheck) && remove(command))
            	// 告知拒绝策略,对该任务进行处理
                reject(command);
            // 根据线程的状态值信息
            // 采取workerCountOf(recheck) 取出 低29 位数据值,即活动线程数
            // 如果活动线程数没了
            else if (workerCountOf(recheck) == 0)
            	// null 表示在线程池创建新的线程,但不启动
            	// boolean ,true表示是core类型,false为maxpoolsize
            	// 创建某个时候会执行的commond
                addWorker(null, false);
        }
        // 1、如果线程池状态不是RUNNING状态
        // 2、如果线程池是RUNNING状态,但是队列塞满了
        // 则进行下列判断
        // 如果将执行任务添加“备用窗口”失败(开启最大maxpool去执行),
		// 但是此时添加执行失败(max全被占用)
        else if (!addWorker(command, false))
        	// 则采取拒绝策略,拒绝掉该Runnable执行体
            reject(command);
    }
    
    private static boolean isRunning(int c) {
    
    
        return c < SHUTDOWN;
    }

Guess you like

Origin blog.csdn.net/qq_38322527/article/details/115148483