Java线程池的那些事(Java线程池详解:从入门到进阶应用指南)

原创
ithorizon 4周前 (10-20) 阅读数 5 #后端开发

Java线程池详解:从入门到进阶应用指南

一、Java线程池简介

Java线程池是一种用于管理线程的工具,它能够有效地管理线程的生命周期,尽大概缩减损耗程序性能。在Java中,线程池的实现核心是通过`java.util.concurrent`包中的`Executor`框架。使用线程池可以避免频繁创建和销毁线程的开销,同时能够合理地复用线程资源。

二、线程池的核心接口和类

Java线程池的核心接口和类如下:

  • `Executor`:线程池的顶层接口,只有一个`execute(Runnable)`方法,用于提交任务。
  • `ExecutorService`:扩展了`Executor`接口,添加了多个功能方法,如`submit()`、`shutdown()`等。
  • `AbstractExecutorService`:实现了`ExecutorService`接口的抽象类,提供了大部分方法的实现。
  • `ThreadPoolExecutor`:`AbstractExecutorService`的实现类,是线程池的核心实现。
  • `ScheduledThreadPoolExecutor`:扩展了`ThreadPoolExecutor`,用于实现定时任务。
  • `Executors`:提供了创建线程池的工厂方法。

三、线程池的创建

Java提供了`Executors`类,它包含了一系列工厂方法用于创建不同类型的线程池:

ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建一个固定大小为10的线程池

ExecutorService executorService1 = Executors.newSingleThreadExecutor(); // 创建一个单线程的线程池

ExecutorService executorService2 = Executors.newCachedThreadPool(); // 创建一个可缓存的线程池

ExecutorService executorService3 = Executors.newScheduledThreadPool(10); // 创建一个定时任务的线程池

四、线程池的参数

创建线程池时,可以设置以下参数:

  • `corePoolSize`:线程池的基本大小。
  • `maximumPoolSize`:线程池最大线程数。
  • `keepAliveTime`:当线程数大于核心线程数时,这是多余空闲线程在终止前等待新任务的最长时间。
  • `unit`:`keepAliveTime`的时间单位。
  • `workQueue`:用来存放任务的队列。
  • `threadFactory`:创建线程的工厂。
  • `handler`:拒绝策略,当任务太多无法处理时,采取的策略。

五、线程池的工作流程

线程池的工作流程如下:

  1. 当提交一个任务时,线程池首先检查是否有空闲的核心线程。
  2. 如果有,则立即执行该任务。
  3. 如果没有,则将任务放入队列。
  4. 如果队列已满,则创建一个新线程,直到约为最大线程数。
  5. 如果约为最大线程数,则采用拒绝策略处理新提交的任务。

六、线程池的拒绝策略

当线程池无法处理新提交的任务时,会采用拒绝策略。Java提供了以下四种拒绝策略:

  • `AbortPolicy`:抛出`RejectedExecutionException`异常。
  • `CallerRunsPolicy`:调用任务的`run()`方法,在调用者线程中直接执行该任务。
  • `DiscardPolicy`:默默丢弃无法处理的任务,不抛出异常。
  • `DiscardOldestPolicy`:丢弃队列中最旧的任务,然后尝试执行新提交的任务。

七、线程池的进阶应用

在实际开发中,我们大概会遇到以下几种场景:

7.1 批量提交任务

使用`ExecutorService`的`invokeAll()`方法可以批量提交任务,并等待所有任务完成。

List> tasks = new ArrayList<>();

tasks.add(() -> "Task1");

tasks.add(() -> "Task2");

tasks.add(() -> "Task3");

ExecutorService executorService = Executors.newFixedThreadPool(3);

try {

List> results = executorService.invokeAll(tasks);

for (Future result : results) {

System.out.println(result.get());

}

} catch (InterruptedException | ExecutionException e) {

e.printStackTrace();

} finally {

executorService.shutdown();

}

7.2 分页提交任务

当任务非常多时,可以分批次提交任务。

public void submitTasks(List tasks, int pageSize) {

ExecutorService executorService = Executors.newFixedThreadPool(10);

int totalSize = tasks.size();

for (int i = 0; i < totalSize; i += pageSize) {

int endIndex = Math.min(i + pageSize, totalSize);

List subList = tasks.subList(i, endIndex);

for (Runnable task : subList) {

executorService.submit(task);

}

}

executorService.shutdown();

}

7.3 定时任务

使用`ScheduledThreadPoolExecutor`可以方便地实现定时任务。

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

executor.schedule(() -> System.out.println("Run after 1 second"), 1, TimeUnit.SECONDS);

executor.shutdown();

八、总结

Java线程池是Java并发编程中非常重要的一个工具,它能够有效地管理线程的生命周期,尽大概缩减损耗程序性能。通过合理地配置线程池参数和选择合适的拒绝策略,我们可以使程序更加高效地运行。同时,掌握线程池的高级应用,如批量提交任务、分页提交任务和定时任务,能够帮助我们更好地应对实际开发中的各种场景。


本文由IT视界版权所有,禁止未经同意的情况下转发

文章标签: 后端开发


热门