线程池机制
**线程池(Thread Pool)**是一种用于管理和复用线程的设计模式。它通过维护一个线程的集合来避免创建和销毁线程的开销,从而提高应用程序的性能和资源利用率。线程池机制广泛用于高并发、异步任务处理等场景。
线程池的基本原理
线程池的核心思想是预先创建一定数量的线程,这些线程会等待处理任务。当有新的任务到来时,线程池会分配一个空闲的线程来执行该任务,而不必重新创建线程。完成任务后,线程不会被销毁,而是返回到池中,等待下一个任务。
线程池的优点
减少资源消耗:通过重用已创建的线程,避免频繁的线程创建和销毁所带来的开销。
提高响应速度:任务到达时不需要等待创建线程,线程池中的空闲线程可以立即执行任务。
增强资源管理:通过控制线程的数量,可以防止资源消耗过多(如CPU、内存等),避免系统因为过度创建线程而崩溃。
可伸缩性:线程池可以根据系统负载动态调整线程的数量,提高并发性能。
Java中的线程池机制
在Java中,java.util.concurrent
包提供了对线程池的支持,ExecutorService
接口和它的几个实现类是线程池的核心组件。
线程池的核心组件
核心线程数(corePoolSize):线程池中始终保持存活的线程数量,即使它们处于空闲状态。
最大线程数(maximumPoolSize):线程池允许创建的最大线程数量。如果任务数量超过了核心线程数,且队列已满,线程池会创建新线程直到达到最大线程数。
任务队列(BlockingQueue):用于存放等待执行的任务。
线程工厂(ThreadFactory):用于创建线程。
拒绝策略(RejectedExecutionHandler):当任务无法执行时的处理策略,比如当线程池已满时新任务的处理方法。
线程池的生命周期:线程池可以被关闭,当线程池关闭后,无法再提交新任务,但已经提交的任务会继续执行完。
Java中的线程池实现
ExecutorService
是Java线程池的核心接口,ThreadPoolExecutor
是它的一个具体实现。常见的创建线程池的方法包括通过Executors
工厂类提供的静态方法:
newFixedThreadPool(int nThreads)
:创建一个固定大小的线程池。
newCachedThreadPool()
:创建一个可根据需要创建新线程的线程池(适用于执行很多短期异步任务)。
newSingleThreadExecutor()
:创建一个单线程的线程池,所有任务将在一个线程中按顺序执行。
newScheduledThreadPool(int corePoolSize)
:创建一个支持定时和周期性任务执行的线程池。
示例:使用固定大小的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池,线程数量为3
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交5个任务到线程池
for (int i = 0; i < 5; i++) {
Runnable task = new WorkerThread("" + i);
executor.execute(task); // 执行任务
}
executor.shutdown(); // 关闭线程池
while (!executor.isTerminated()) {
}
System.out.println("All tasks finished.");
}
}
class WorkerThread implements Runnable {
private String command;
public WorkerThread(String command) {
this.command = command;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " End.");
}
private void processCommand() {
try {
Thread.sleep(2000); // 模拟执行任务
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
pool-1-thread-1 Start. Command = 0
pool-1-thread-2 Start. Command = 1
pool-1-thread-3 Start. Command = 2
pool-1-thread-2 End.
pool-1-thread-1 End.
pool-1-thread-3 End.
pool-1-thread-1 Start. Command = 3
pool-1-thread-3 Start. Command = 4
pool-1-thread-1 End.
pool-1-thread-3 End.
All tasks finished.
解释:
创建了一个大小为3的固定线程池。即线程池中最多同时有3个线程运行。
使用executor.execute(task)
提交了5个任务,但线程池只能并行执行3个任务,剩下的任务会被放到队列中等待线程空闲。
当所有任务执行完毕后,调用executor.shutdown()
来关闭线程池,防止新的任务提交。
线程池的工作流程:
当任务提交时,如果线程池中的活跃线程数小于核心线程数,那么立即创建一个新的线程来处理任务。
如果活跃线程数达到核心线程数,那么任务会被放入任务队列等待。
当任务队列满了且活跃线程数小于最大线程数时,线程池会创建新的线程来处理任务。
如果活跃线程数达到最大线程数且队列也满了,那么新任务会根据拒绝策略进行处理(默认是抛出异常)。