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

9

我对于executor何时创建新线程感到困惑。我的理解是:对于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());

4
您可以使用调试器来回答这些问题,或者查看 Executors 的代码。 - Oliver Charlesworth
这些方法中的每一个都有一个接受ThreadFactory的变体,您可以传入自己的实现,在请求线程时记录它。 - pvg
1个回答

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

为了更好地理解这一点,正如@Oliver建议的那样,您需要阅读Java源代码,并阅读关于ThreadPoolExecutor的内容,特别是核心池大小、最大池大小等。如果您想用通俗易懂的话快速理解这一点,那么请阅读这个好答案

现在,在我带您浏览一些示例代码之前,请先了解以下几个重要的方面:

  • Executors是Java的工具类,用于创建并返回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());
            }
        });
    }

}

输出:

### 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

1
非常清楚。我通常閱讀Java文檔,但我覺得閱讀源代碼對我來說很困難。 - user7328234
谢谢,没问题。许多专家说,在Java中检查和尝试理解源代码是最好的理解方式。 - hagrawal7777

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接