ThreadPoolExecutor.execute(Runnable command)何时创建新线程

ThreadPoolExecutor.execute(Runnable command) when to create a new thread

我正在阅读 ThreadPoolExecutor.java 的源代码,用于下面的 execute 方法:

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

假设线程池有2个核心线程,最大池大小设置为4。

我能理解代码if (workerCountOf(c) < corePoolSize) { addWorkder(..) },这意味着如果当前核心线程数小于核心轮询大小,只需创建一个新线程来处理可运行命令。

我无法理解的是,如果我们已经调用了两次execute(runnable),而且每次都需要很长时间才能完成,所以他们现在还在忙,现在我们正在调用第3次.

代码会做什么?我认为代码转到 if (isRunning(c) && workQueue.offer(command)) { 因此命令被添加到工作队列中。但是,我不明白这第三个命令将由哪个线程执行。根据代码 else if (workerCountOf(recheck) == 0),我认为 worker count 应该是 2,因为我们已经添加了两个 worker。

所以我的问题是第 3 个工人什么时候加入?

--编辑--

我的测试代码:


public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                2,
                4,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4)
        );

        threadPoolExecutor.execute(new Command("A"));
        threadPoolExecutor.execute(new Command("B"));
        threadPoolExecutor.execute(new Command("C"));

    }

    static class Command implements Runnable {
        private String task;
        Command(String task) {
            this.task = task;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000 * 10);
                System.out.println(new Date() + " - " + Thread.currentThread().getName() + " : " + task);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

它打印:

Thu Jun 13 17:44:30 CST 2019 - pool-1-thread-1 : A
Thu Jun 13 17:44:30 CST 2019 - pool-1-thread-2 : B
Thu Jun 13 17:44:40 CST 2019 - pool-1-thread-1 : C

根据测试代码,我预计核心工作人员会持续忙碌 10 秒,所以当 execute("C") 我想解决这个问题时 'core workers are busy and the 3rd worker will be added',但似乎没有第 3 个工作人员?抱歉,有什么问题吗?

谢谢。

I want to hit the case 'core workers are busy and the 3rd worker will be added'

那你也得去排队

Javadoc 说:

When a new task is submitted in method execute(java.lang.Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full.

假设

   N = no of thread in currently in the pool.
   C = core size of pool
   M = maximum size of pool.
   BQ = Bounded Blocking Queue.(having a predefined capacity).
   UQ = Unbounded Blocking Queue.(without a predefined capacity).
   DHQ = Direct hand-offs Queue.

然后

       1. If BQ

           A. If N <= C , then thread always created when task is submitted, idle 
              thread is  present in pool or not doesn't matter.
           B. Once the core pool size is reached, executor start puting 
              the new task in queue if there is no idle thread. 
              If there is any idle thread then the task is assigned to idle thread.
           C. When BQ is full, then executor start creating again new thread till 
              its value reached to M if there is no idle thread.
              So the new thread creation after reaching N=C value is start when queue 
              is full.
           D. Once N=M reached and BQ is also full , then executor not accept any 
              task.It throw exception.

      2. If UQ 

           A. Same as above
           B. Same as above
           C. Not applicable. Why ? because it is unbounded queue.
              (UQ capacity is Integer.MAX_VALUE)
           D. No effect of M. Why ? 
              Since creation of new thread again is start after the queue is full,but 
              in the case UQ queue is never full. 
              So new thread never created once reach N=C for the new task submitted. 
              Means thread in thread pool always be equal to C (N=C always) in case 
              UQ , whatever the value of M


     3. If DHQ 
          A. The direct hand-offs queue never put the task in queue, its immediately
             assigned task to thread if any thread is idle ,if not then it create new 
             one.(task in queue is always 0)
          B. The concept of C is not applicable in this queue.Thread created till 
             its value reach M.
          C. Once the N value reach M (N=M), and try to submit the task ,it reject 
             the task.