Java中ExecutorService的start方法何时被调用?线程启动节点解析
核心结论
新线程(执行任务的工作线程)在调用submit()方法时就可能启动并执行任务,而非等到调用Future.get()时才启动。start()方法由线程池内部负责调用,不需要开发者手动触发。
详细解释
1. FixedThreadPool的工作机制
你使用的Executors.newFixedThreadPool(3)会创建一个核心线程数和最大线程数均为3的线程池,任务队列是无界的LinkedBlockingQueue:
- 线程池默认不会预先创建核心线程,而是在第一次提交任务时开始创建。
- 当你调用
submit()提交任务时,线程池会判断当前核心线程数是否已达上限:- 如果核心线程未填满,会直接创建新的工作线程,调用线程的
start()方法,线程启动后立即执行提交的任务。 - 如果核心线程已全部处于忙碌状态,任务会被放入等待队列,直到有空闲线程来处理。
- 如果核心线程未填满,会直接创建新的工作线程,调用线程的
在你的代码中,你提交了3个任务,正好匹配线程池的核心线程数,因此每个任务提交时都会触发一个新线程的创建与启动,三个任务会并行执行,不需要等到调用get()。
2. start()方法的调用位置
线程池内部会将任务封装为Worker对象(实现了Runnable接口),当需要创建新工作线程时,线程池会:
- 以
Worker为目标创建Thread实例。 - 调用该
Thread的start()方法,启动线程。 - 线程启动后,会执行
Worker.run()方法,该方法会循环从任务队列中获取任务并执行。
这个过程完全由线程池(ThreadPoolExecutor的内部逻辑)处理,开发者无需手动调用start()。
3. Future.get()的作用
Future.get()的唯一作用是阻塞当前线程,等待任务执行完成,并获取任务的返回结果。它不会触发任务的启动,任务在submit()时就已经开始执行(如果线程池有资源的话)。
在你的代码中,executorService.awaitTermination(3, TimeUnit.SECONDS)会等待线程池中的任务完成,之后调用get()只是获取已经执行完成的结果;如果任务还没执行完,get()会继续阻塞直到任务结束。
补充说明
如果线程池中的工作线程处于空闲状态(比如之前的任务已经执行完毕),此时提交新任务,线程池会直接将任务分配给空闲线程,不需要重新创建线程(也就不会再次调用start(),因为线程只能被启动一次),任务会立即在空闲线程上开始执行。
内容的提问来源于stack exchange,提问作者elvis

