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

时间:2019-06-13 09:19:18

标签: java multithreading threadpoolexecutor

我正在为以下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),并且每个人都需要很长时间才能完成,所以他们现在仍然很忙,现在我们是第三次打电话。 / p>

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

所以我的问题是,什么时候会增加第三个工作人员?

-编辑-

我的测试代码:


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")遇到“核心工作人员忙碌并且将增加第3个工作人员”的情况时,但是似乎没有第三工人?抱歉,怎么了?

谢谢。

2 个答案:

答案 0 :(得分:2)

  

我想打个比方说“核心工作人员很忙,将增加第三个工作人员”

然后,您还必须填写队列。

Javadoc说:

  

当在方法execute(java.lang.Runnable)中提交新任务,并且正在运行的线程少于corePoolSize线程时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理请求。如果正在运行的corePoolSize线程多但少于maximumPoolSize线程,则仅当队列已满时才会创建新线程

答案 1 :(得分:0)

假设

   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.