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

时间:2017-04-23 09:25:55

标签: 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());

1 个答案:

答案 0 :(得分:2)

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

为了更好地理解这一点,正如@Oliver建议你需要浏览Java源代码并阅读ThreadPoolExecutor,特别是核心池大小,最大池大小等等。如果你想快速用外行的话理解这一点,然后阅读this good answer

现在,在我向您介绍一些示例代码之前,以下几点是很难理解的:

  • Java的实用程序类Executors将创建并返回ExecutorService的对象(请注意ExecutorService是一个接口)。
  • 现在,如果是newCachedThreadPool()newFixedThreadPool(int nThreads),您将获得ThreadPoolExecutor的对象(请注意ThreadPoolExecutor实现ExecutorService接口。)
  • 正如您在源代码中所看到的,当您执行Executors.newFixedThreadPool(3);时,您只获得ThreadPoolExecutor的对象,其中包含所有实例变量,如核心池大小,最大池大小等设置,以及你的情况将被设置为3。
  • 此时没有创建任何线程,只有当您使用executesubmitinvokeAll开始执行任务时才会创建实际线程。
  • 正如您在源代码中看到的,当您第一次执行execute时,如果当前池大小小于核心池大小,它将只创建一个新线程,因此这是您的线程开始创建的位置。

请参阅下面的示例代码,它将帮助您了解并证明只有在您开始执行任务时才创建线程。 为了解释你,我做的主要技巧是使用了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