Java中常见创建线程池的几种方法。
1. 使用 Executors
工具类创建线程池
newFixedThreadPool(int nThreads)
- 特点:创建一个固定大小的线程池,线程池中的线程数始终保持不变。
- 适用场景:适用于任务量已知且相对固定的场景,可以有效控制资源的使用。
newSingleThreadExecutor()
- 特点:创建一个单线程的线程池,所有任务按顺序执行,一次只有一个任务处于活动状态。
- 适用场景:适用于需要按顺序执行任务的场景,确保任务的顺序性和互斥性。
newCachedThreadPool()
- 特点:创建一个可缓存的线程池,线程池会根据需要创建新线程,但在先前构建的线程可用时将重用它们。空闲线程会在60秒后被终止。
- 适用场景:适用于执行大量短期异步任务的场景,可以快速响应和处理任务。
newScheduledThreadPool(int corePoolSize)
- 特点:创建一个固定大小的线程池,可以延迟或周期性地执行任务。
- 适用场景:适用于需要定时或周期性执行任务的场景,如定时任务调度。
newSingleThreadScheduledExecutor()
- 特点:创建一个单线程的线程池,可以延迟或周期性地执行任务。
- 适用场景:适用于需要按顺序执行定时任务的场景,确保任务的顺序性和互斥性。
newWorkStealingPool(int parallelism)
- 特点:创建一个工作窃取线程池,使用
ForkJoinPool
实现,支持并行处理任务。线程池中的线程会尝试“窃取”其他线程的任务来执行。 - 适用场景:适用于需要并行处理大量任务的场景,可以充分利用多核处理器的性能。
2. 使用 ThreadPoolExecutor
类创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()
);
其中corePoolSize是线程池的核心线程数,maximumPoolSize是线程池的最大线程数,keepAliveTime是非核心线程空闲时间,TimeUnit.MILLISECONDS表示时间单位,new LinkedBlockingQueue()是任务队列。
- 特点:使用 ThreadPoolExecutor 可以更灵活地配置线程池的各个参数,例如核心线程数、最大线程数、线程空闲时间和任务队列类型等。
- 适用场景:适用于需要高度定制化线程池的场景,可以根据具体需求调整线程池的参数。
3. 使用 ScheduledExecutorService
创建定时任务线程池
ScheduledExecutorService executor = Executors.newScheduledThreadPool(nThreads);
- 特点:创建一个固定大小的线程池,可以执行定时任务。
- 适用场景:适用于需要定时或周期性执行任务的场景,如定时任务调度。
总结
-
newFixedThreadPool
:固定大小的线程池,适用于任务量已知且相对固定的场景,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads; -
newSingleThreadExecutor
:单线程的线程池,适用于需要按顺序执行任务的场景,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目; -
newCachedThreadPool
:可缓存的线程池,适用于执行大量短期异步任务的场景,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列; -
newScheduledThreadPool
:固定大小的线程池,支持定时任务,适用于需要定时或周期性执行任务的场景,和 newSingleThreadScheduledExecutor()类似,创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程; -
newSingleThreadScheduledExecutor
:单线程的线程池,支持定时任务,适用于需要按顺序执行定时任务的场景,返回 ScheduledExecutorService,可以进行定时或周期性的工作调度; -
newWorkStealingPool
:工作窃取线程池,支持并行处理任务,适用于需要并行处理大量任务的场景。这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序; -
ThreadPoolExecutor
:是最原始的线程池创建,高度定制化的线程池,适用于需要精确控制线程池行为的场景。