跳转到内容

Java线程池

来自代码酷

Java线程池[编辑 | 编辑源代码]

简介[编辑 | 编辑源代码]

Java线程池是Java多线程编程中的核心组件,它通过复用线程来减少创建和销毁线程的开销,提高系统性能和资源利用率。线程池属于`java.util.concurrent`包的一部分,是Executor框架的核心实现。

线程池的主要优势包括:

  • 资源节约:避免频繁创建/销毁线程
  • 性能提升:减少线程创建延迟
  • 线程管理:提供统一的线程生命周期控制
  • 任务队列:支持任务缓冲和调度

核心概念[编辑 | 编辑源代码]

线程池组成[编辑 | 编辑源代码]

Java线程池主要由以下组件构成: 1. 工作线程(Worker Threads):执行任务的线程 2. 任务队列(BlockingQueue):存放待执行任务 3. 线程工厂(ThreadFactory):创建新线程 4. 拒绝策略(RejectedExecutionHandler):处理无法执行的任务

graph TD A[提交任务] --> B{核心线程是否满?} B -->|否| C[创建新线程执行] B -->|是| D{队列是否满?} D -->|否| E[任务入队列] D -->|是| F{线程数是否达最大值?} F -->|否| G[创建新线程执行] F -->|是| H[执行拒绝策略]

线程池类型[编辑 | 编辑源代码]

Java通过`Executors`类提供了几种常用线程池:

1. 固定大小线程池[编辑 | 编辑源代码]

```java ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); ```

  • 特点:固定数量的线程
  • 适用场景:已知并发量的稳定负载

2. 可缓存线程池[编辑 | 编辑源代码]

```java ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); ```

  • 特点:自动扩展/收缩线程数
  • 适用场景:大量短期异步任务

3. 单线程池[编辑 | 编辑源代码]

```java ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); ```

  • 特点:单线程顺序执行
  • 适用场景:需要任务顺序执行的场景

4. 定时线程池[编辑 | 编辑源代码]

```java ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); ```

  • 特点:支持定时/周期性任务
  • 适用场景:定时任务、延迟任务

核心参数详解[编辑 | 编辑源代码]

通过`ThreadPoolExecutor`构造函数可自定义线程池:

```java public ThreadPoolExecutor(

   int corePoolSize,      // 核心线程数
   int maximumPoolSize,   // 最大线程数
   long keepAliveTime,    // 空闲线程存活时间
   TimeUnit unit,        // 时间单位
   BlockingQueue<Runnable> workQueue, // 任务队列
   ThreadFactory threadFactory,      // 线程工厂
   RejectedExecutionHandler handler  // 拒绝策略

) ```

参数配置示例[编辑 | 编辑源代码]

```java ThreadPoolExecutor executor = new ThreadPoolExecutor(

   2, // 核心线程数
   5, // 最大线程数
   60, // 空闲时间
   TimeUnit.SECONDS,
   new ArrayBlockingQueue<>(10), // 容量为10的队列
   Executors.defaultThreadFactory(),
   new ThreadPoolExecutor.AbortPolicy() // 默认拒绝策略

); ```

任务执行流程[编辑 | 编辑源代码]

1. 任务提交后,优先使用核心线程执行 2. 核心线程忙时,任务进入队列 3. 队列满时,创建非核心线程(不超过maximumPoolSize) 4. 线程数达最大值且队列满时,触发拒绝策略

拒绝策略[编辑 | 编辑源代码]

Java提供四种内置拒绝策略: 1. AbortPolicy:默认策略,抛出RejectedExecutionException 2. CallerRunsPolicy:由提交任务的线程直接执行 3. DiscardPolicy:静默丢弃任务 4. DiscardOldestPolicy:丢弃队列中最旧的任务

代码示例[编辑 | 编辑源代码]

基础使用示例[编辑 | 编辑源代码]

```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;

public class ThreadPoolExample {

   public static void main(String[] args) {
       // 创建固定大小的线程池
       ExecutorService executor = Executors.newFixedThreadPool(3);
       
       // 提交10个任务
       for (int i = 1; i <= 10; i++) {
           final int taskId = i;
           executor.execute(() -> {
               System.out.println("执行任务 " + taskId + " 线程: " + Thread.currentThread().getName());
               try {
                   Thread.sleep(1000); // 模拟任务耗时
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });
       }
       
       // 关闭线程池
       executor.shutdown();
   }

} ```

输出示例: ``` 执行任务 1 线程: pool-1-thread-1 执行任务 2 线程: pool-1-thread-2 执行任务 3 线程: pool-1-thread-3 执行任务 4 线程: pool-1-thread-1 执行任务 5 线程: pool-1-thread-2 ... ```

自定义线程池示例[编辑 | 编辑源代码]

```java import java.util.concurrent.*;

public class CustomThreadPool {

   public static void main(String[] args) {
       ThreadPoolExecutor executor = new ThreadPoolExecutor(
           2, 4, 30, TimeUnit.SECONDS,
           new ArrayBlockingQueue<>(2),
           new ThreadPoolExecutor.CallerRunsPolicy()
       );
       
       for (int i = 1; i <= 8; i++) {
           final int taskId = i;
           executor.execute(() -> {
               System.out.println("任务 " + taskId + " 由 " + Thread.currentThread().getName() + " 执行");
               try {
                   Thread.sleep(2000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });
           System.out.println("队列大小: " + executor.getQueue().size());
       }
       
       executor.shutdown();
   }

} ```

最佳实践[编辑 | 编辑源代码]

1. 合理配置线程数

  * CPU密集型任务:Nthreads=Ncpu+1
  * IO密集型任务:Nthreads=2×Ncpu

2. 避免使用无界队列:可能导致内存溢出

3. 正确处理异常: ```java executor.submit(() -> {

   try {
       // 任务代码
   } catch (Exception e) {
       // 异常处理
   }

}); ```

4. 优雅关闭: ```java executor.shutdown(); // 平缓关闭 executor.shutdownNow(); // 立即关闭 ```

实际应用场景[编辑 | 编辑源代码]

Web服务器请求处理[编辑 | 编辑源代码]

典型的三层线程池架构: 1. 接收层:单线程接受连接 2. 处理层:线程池处理请求 3. IO层:专用线程池处理阻塞IO

批量数据处理[编辑 | 编辑源代码]

```java // 处理10000条数据 List dataList = getDataList(); ExecutorService executor = Executors.newFixedThreadPool(8);

List<Future<Result>> futures = new ArrayList<>(); for (Data data : dataList) {

   futures.add(executor.submit(() -> processData(data)));

}

// 获取结果 for (Future<Result> future : futures) {

   Result result = future.get();
   // 处理结果

} ```

常见问题[编辑 | 编辑源代码]

线程池大小选择[编辑 | 编辑源代码]

  • 太小:无法充分利用CPU
  • 太大:增加上下文切换开销

任务堆积处理[编辑 | 编辑源代码]

  • 监控队列大小:`executor.getQueue().size()`
  • 动态调整线程数:`executor.setCorePoolSize()`

死锁风险[编辑 | 编辑源代码]

避免任务间相互等待,特别是在使用同线程池时

性能监控[编辑 | 编辑源代码]

可通过以下方法监控线程池状态: ```java // 活动线程数 int activeCount = executor.getActiveCount();

// 已完成任务数 long completedTaskCount = executor.getCompletedTaskCount();

// 队列中的任务数 int queueSize = executor.getQueue().size(); ```

总结[编辑 | 编辑源代码]

Java线程池是多线程编程的强大工具,正确使用可以:

  • 提高系统吞吐量
  • 降低资源消耗
  • 提供更好的可管理性

关键点:

  • 根据场景选择合适的线程池类型
  • 合理配置核心参数
  • 实现适当的拒绝策略
  • 监控和调优线程池性能