最近面试问道了线程池的创建方式,这里出一篇文章记录下这一知识点!
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的ThreadFactory创建一个新线程。
线程池的创建主要依赖于java.util.concurrent
包下的ExecutorService
和Executors
类。最近面试问到了这块,所以这篇文章我们将详细介绍几种常见的线程池创建方式。
FixedThreadPool
FixedThreadPool
是一种固定大小的线程池。它的核心线程数和最大线程数都是创建时指定的数值,且不会变化。就算空闲,也不会回收线程,除非设置了allowCoreThreadTimeOut
。
举个栗子:我们创建一个固定大小为5的线程池,并提交10个任务。由于线程池的大小固定为5,因此这5个线程会并发执行,而剩下的任务会等待前面的任务完成后再执行。
代码如下:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FixedThreadPoolDemo { public static void main(String[] args) { // 创建一个固定大小的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("" + i); executorService.execute(worker); // 执行任务 } executorService.shutdown(); // 关闭线程池 while (!executorService.isTerminated()) { } System.out.println("所有任务已完成"); } } class WorkerThread implements Runnable { private String command; public WorkerThread(String s) { this.command = s; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 开始. 命令 = " + command); processCommand(); System.out.println(Thread.currentThread().getName() + " 结束."); } private void processCommand() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }
CachedThreadPool
CachedThreadPool
是一种缓存线程池,它的线程数量是不定的,可以说是几乎无限的。当提交一个任务时,如果线程池中有空闲线程,则立即执行;如果没有,则创建一个新线程执行。当线程空闲超过60秒,则自动回收。
举个栗子:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CachedThreadPoolDemo { public static void main(String[] args) { // 创建一个可缓存的线程池 ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("" + i); executorService.execute(worker); // 执行任务 } executorService.shutdown(); // 关闭线程池 while (!executorService.isTerminated()) { } System.out.println("所有任务已完成"); } }
CachedThreadPool`适合执行大量的耗时较少的任务,如Web服务器。
SingleThreadExecutor
SingleThreadExecutor
是一个单线程的Executor,它使用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SingleThreadExecutorDemo { public static void main(String[] args) { // 创建一个单线程的线程池 ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread("" + i); executorService.execute(worker); // 执行任务 } executorService.shutdown(); // 关闭线程池 while (!executorService.isTerminated()) { } System.out.println("所有任务已完成"); } }
在SingleThreadExecutor
中,由于只有一个线程,因此任务会按照提交的顺序一个接一个地执行,不会出现并发的情况。
ScheduledThreadPool
ScheduledThreadPool
是 Java 并发包 java.util.concurrent
中提供的一个线程池实现,它用于在给定的延迟后运行命令,或者定期地执行命令。ScheduledThreadPool
的主要特点是能够处理需要定时执行或周期性执行的任务。
举个栗子:
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledThreadPoolDemo { public static void main(String[] args) { // 创建一个ScheduledThreadPool,包含3个核心线程 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); // 提交一个Runnable任务,在延迟2秒后执行 scheduledExecutorService.schedule(new RunnableTask("一次性任务"), 2, TimeUnit.SECONDS); // 提交一个Runnable任务,初始延迟2秒,之后每隔1秒执行一次 scheduledExecutorService.scheduleAtFixedRate(new RunnableTask("周期性任务"), 2, 1, TimeUnit.SECONDS); // 通常我们需要在程序结束时关闭线程池 // scheduledExecutorService.shutdown(); } static class RunnableTask implements Runnable { private String command; public RunnableTask(String command) { this.command = command; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " 开始执行命令: " + command + " at " + System.currentTimeMillis()); } } }
我们创建了一个 ScheduledThreadPool
,它包含3个核心线程。然后,我们提交了两个任务:
- 一个是一次性任务,它在提交后的2秒后开始执行。
- 另一个是周期性任务,它在提交后的2秒开始执行,然后每隔1秒执行一次。
除了以上的用法
,ScheduledExecutorService
提供了几个用于定时执行任务的方法:
schedule(Runnable command, long delay, TimeUnit unit)
:在给定延迟后运行命令一次。scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
:初始延迟后开始首次执行,然后随后每隔固定周期执行一次。scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
:初始延迟后开始首次执行,然后每次执行完毕后等待固定延迟再次执行。
如果任务执行过程中抛出异常,那么 ScheduledThreadPool
会停止该任务的后续执行,但不会停止线程池本身或其他任务的执行。如果需要处理任务执行中的异常,可以在任务内部进行捕获和处理。
以上就是创建线程池的几种方式,本篇文章到此结束,谢谢大家的观看!