执行者何时真正创建新线程

use*_*234 8 java multithreading

我在为执行程序创建新线程时感到困惑.我的理解是:对于cachedthreadpool,根据任务的提交创建新线程.对于fixedthreadpool和singlethread,无论提交任务如何,都会提前创建线程.我的理解错了吗?

ExecutorService exec = Executors.newCachedThreadPool(); 
exec.execute(new LiftOff());

ExecutorService exec = Executors.newFixedThreadPool(3); // Are the three threads created 
                                                        // after this line executes?
exec.execute(new LiftOff());

ExecutorService exec = Executors.newSingleThreadExecutor(); // Is the single thread created 
                                                            // after this line executes?
exec.execute(new LiftOff());
Run Code Online (Sandbox Code Playgroud)

hag*_*wal 4

简短的回答是,在您提到的所有情况下,仅当您开始执行任务时才会创建线程,即执行此行后不会创建任何线程,并且仅在执行ExecutorService exec = Executors.newFixedThreadPool(3);此行后才会创建第一个线程。exec.execute(new LiftOff());


为了更好、更全面地理解这一点,正如 @Oliver 建议的那样,您需要浏览 Java 源代码并阅读有关ThreadPoolExecutor 的信息,特别是核心池大小、最大池大小等。如果您想用外行人的话快速理解这一点,请阅读这个好答案

现在,在我带您了解一些示例代码之前,以下是一些需要理解的要点:

  • Java的实用程序类Executors将创建并返回对象ExecutorService(请注意ExecutorService是一个接口)。
  • 现在,在 的情况下newCachedThreadPool()newFixedThreadPool(int nThreads)您将得到一个对象ThreadPoolExecutor(请注意,它ThreadPoolExecutor实现了ExecutorService接口)。
  • 正如你在源代码中看到的,当你这样做时Executors.newFixedThreadPool(3);,你只能得到一个对象ThreadPoolExecutor其中设置了所有实例变量,如核心池大小、最大池大小等,在您的情况下,它将设置为 3。
  • 此时不会创建任何线程,并且仅当您开始使用或execute开始执行任务时才会创建实际的线程submitinvokeAll执行任务时才会创建实际的线程。
  • 正如您在源代码中看到的,当您第一次执行此操作时execute,如果当前池大小小于核心池大小,它将仅创建 1 个新线程,因此这就是您开始创建线程的地方。

请参阅下面的示例代码,它将帮助您理解并证明线程仅在您开始执行任务时才创建。为了解释一下,我所做的主要技巧是我使用了对象引用变量ThreadPoolExecutor,以便我可以调用类似的方法getPoolSize()(请注意,它getPoolSize()告诉池中当前存在多少个线程),因为当您使用对象引用变量时ExecutorService您无法调用这些方法(我确信我不需要告诉“为什么”)。

当您运行此示例时,您会注意到

  • 之后没有创建任何线程ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
  • 首先,executeRunnable(poolExecutor);您在池中获得了一个线程。
  • 由于您使用的核心池大小为 3,因此在创建 3 个线程后,不再创建更多线程。(请阅读有关核心、最大池大小和“队列”大小的信息)

package com.learn.stackoverflow.multithreading;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 
 * @author himanshu.agrawal
 *
 */
public class ExecutorServiceNumberOfThreads {
    public static void main(String[] args) {
        System.out.println("### Testing Executors.newFixedThreadPool()");
        testNewFixedThreadPool();
    }

    private static void testNewFixedThreadPool() {
        ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
        System.out.println("Pool when no execute() : " + poolExecutor.getPoolSize());
        executeRunnable(poolExecutor);
        System.out.println("Pool after 1st execute() : " + poolExecutor.getPoolSize());
        executeRunnable(poolExecutor);
        System.out.println("Pool after 2nd execute() : " + poolExecutor.getPoolSize());
        executeRunnable(poolExecutor);
        System.out.println("Pool after 3rd execute() : " + poolExecutor.getPoolSize());
        executeRunnable(poolExecutor);
        System.out.println("Pool after 4th execute() : " + poolExecutor.getPoolSize());
        executeRunnable(poolExecutor);
        System.out.println("Pool after 5th execute() : " + poolExecutor.getPoolSize());
    }

    private static void executeRunnable(ThreadPoolExecutor poolExecutor) {
        poolExecutor.execute(new Runnable() {

            @Override
            public void run() {
                System.out.println("Running: " + Thread.currentThread().getId() + " | " + new Date());
            }
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

输出:

### Testing Executors.newFixedThreadPool()
Pool when no execute() : 0
Pool after 1st execute() : 1
Pool after 2nd execute() : 2
Pool after 3rd execute() : 3
Pool after 4th execute() : 3
Pool after 5th execute() : 3
Running: 10 | Sun Apr 23 19:50:32 IST 2017
Running: 8 | Sun Apr 23 19:50:32 IST 2017
Running: 10 | Sun Apr 23 19:50:32 IST 2017
Running: 9 | Sun Apr 23 19:50:32 IST 2017
Running: 8 | Sun Apr 23 19:50:32 IST 2017
Run Code Online (Sandbox Code Playgroud)