当前位置: 首页 > news >正文

线程池相关介绍

一、线程池

1、概念:

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建的线程集合中自动执行这些队列任务。

2、作用:

线程池的主要作用是管理线程资源,避免频繁创建和销毁线程带来的性能开销,提高程序的执行效率和稳定性。

3、过程:

核心方法:submit(Runnable),通过Runnable描述一段要执行的任务,通过submit将任务放到线程池里面,此时线程池里面的线程就会执行这样的任务。

二、线程池参数介绍

1、核心参数

java的标准库里面提供了直接使用的线程池ThreadPoolExecutor,包含7个核心参数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler
)

接下来我们详细介绍这7个参数。 

2、corePoolSize(核心线程数)

(1)表示至少多少个线程,线程池一旦创建,这些线程也会创建,直到整个线程池销毁,这些线程才销毁。

(2)作用:线程池长期保持的线程数量,即使线程处于空闲状态也不会销毁(除非设置了allowCoreThreadTimeOut)。

(3)示例:corePoolSize=5表示线程池至少保留5个线程。

3、maximumPoolSize(最大线程数)

(1)表示线程池中的核心线程+非核心线程(不繁忙就销毁,繁忙就在创建)。

(2)作用:线程池允许创建的最大线程数量。

(3)与任务队列的关系:当核心线程满且任务队列已满时,线程池会创建新线程直到达到最大线程数。

这个关系可能有点难理解,主要和工作流程有关,下面会介绍,我们可以举一个生活中的场景来理解:

假设你经营一家餐厅,核心线程数就是长期雇佣的全职厨师,任务队列可以比作餐厅内的等待座位(例如最多坐 5 人),而最大线程数就是最多能雇佣的厨师数量。
顾客来之后,如果核心线程未满,则新顾客直接入座,全职厨师立即做菜,核心线程已满,那么新顾客进入候餐区等待,如果候餐区已满,此时餐厅会临时雇佣兼职厨师(创建新线程),直到总厨师数达到最大线程数。
最后如果总厨师数已满且候餐区已满:拒绝新顾客(触发拒绝策略)。

4、keepAliveTime(线程空闲超时时间)

(1)作用:当线程数量超过核心线程数时,多余的空闲线程在被销毁前等待新任务的最长时间。

(2)配置:需配合TimeUnit参数指定时间单位(如秒、毫秒)。 

5、TimeUnit(java中的枚举类)

(1)作用:定义了7种时间单位

NANOSECONDS(纳秒)
MICROSECONDS(微秒)
MILLISECONDS(毫秒)
SECONDS(秒)
MINUTES(分钟)
HOURS(小时)
DAYS(天)

6、workQueue(任务队列)

(1) 作用:存储待执行的任务,仅当核心线程已满时,新任务才会进入队列。

(2)选择使用数组/链表;指定容量capacity;指定是否要带有优先级/比较规则;

(3)常用队列类型:
ArrayBlockingQueue:有界队列,需指定容量。
LinkedBlockingQueue:无界队列(默认容量为Integer.MAX_VALUE),可能导致 OOM。
SynchronousQueue:直接提交队列,不存储任务,需配合无界线程数使用。

7、threadFactory(线程工厂)

(1)作用:创建线程的工厂类,可自定义线程名称、优先级等属性。(统一构造并初始化线程)

(2)工厂模式也是一种设计模式,和单例模式是并列关系。

(3)工厂方法的核心是通过静态方法把构造对象new的过程、各种属性初始化过程封装起来了,提供多组静态方法实现不同的情况。

8、handler(拒绝策略)

(1)作用:当任务队列和线程池都满时,对新提交任务的处理策略。(可以结合第3点的生活场景理解)

(2)内置策略

AbortPolicy(默认):直接抛出RejectedExecutionException,线程池可能无法继续工作
CallerRunsPolicy:让调用submit的线程自行执行任务。
DiscardPolicy:静默丢弃新任务,当前submit的这个任务。
DiscardOldestPolicy:丢弃队列中最老的任务,尝试重新提交当前任务。

三、线程池工作流程

1、线程初始化

(1)参数配置:创建线程池时需指定核心参数(如核心线程数、最大线程数、任务队列类型等)。

(2)线程创建:初始化时默认不创建线程,直到有任务提交。

2、任务提交流程

当调用submit()或execute()提交任务时,线程池按以下顺序处理:

3、任务执行与线程复用

(1)工作线程循环:线程启动后进入无限循环,从队列中获取任务并执行:

while (true) {Runnable task = workQueue.take();  // 阻塞获取任务task.run();
}

(2)线程复用:任务执行完毕后,线程不会立即销毁,而是继续等待下一个任务,实现复用。

(3)超时销毁:非核心线程空闲时间超过keepAliveTime时会被销毁,核心线程默认保留。

4、拒绝策略处理

当线程池和队列均满时,新任务会触发拒绝策略。(详见第二部分四种内置策略)

5、关闭线程池

调用shutdown()或shutdownNow()终止线程池

(1)shutdown():平缓关闭,不再接受新任务,但会执行完队列中已有的任务。

(2)shutdownNow():强制关闭,尝试中断正在执行的任务,并返回队列中未执行的任务列表。

executor.shutdown();  // 平缓关闭
try {if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {executor.shutdownNow();  // 超时未关闭则强制关闭}
} catch (InterruptedException e) {executor.shutdownNow();
}

四、使用Executors 创建常见的线程池

Executors 类提供了一系列工厂方法,用于快速创建不同类型的线程池。

返回类型是ExecutorService,通过ExecutorService.submit可以注册⼀个任务到线程池中。

1、newFixedThreadPool(固定大小线程池)

创建固定数量线程的线程池,适用于需要控制并发线程数的场景。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class FixedThreadPoolExample {public static void main(String[] args) {// 创建包含5个线程的固定大小线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 提交10个任务for (int i = 0; i < 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

特点:核心线程=最大线程数,线程数量固定

2、newCachedThreadPool(缓存线程池)

创建可根据需要动态扩展的线程池,适用于执行大量短期异步任务的场景。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CachedThreadPoolExample {public static void main(String[] args) {// 创建缓存线程池ExecutorService executor = Executors.newCachedThreadPool();// 提交大量短期任务for (int i = 0; i < 100; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();}
}

特点: 

核心线程数 = 0,最大线程数 = Integer.MAX_VALUE(理论无限)。
线程空闲 60 秒后自动回收,适用于短期任务。
使用SynchronousQueue,任务直接提交给线程处理,不排队。
风险:可能创建过多线程导致系统资源耗尽。

3、newSingleThreadExecutor(单线程线程池) 

创建只有一个工作线程的线程池,确保任务按顺序执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SingleThreadExecutorExample {public static void main(String[] args) {// 创建单线程线程池ExecutorService executor = Executors.newSingleThreadExecutor();// 提交多个任务for (int i = 0; i < 5; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();}
}

特点:

核心线程数 = 最大线程数 = 1,确保任务串行执行。
使用无界队列,任务按提交顺序执行。
适用于需要顺序执行任务且不允许并发的场景。 

4、newScheduledThreadPool(定时任务线程池) 

创建支持定时或周期性执行任务的线程池。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolExample {public static void main(String[] args) {// 创建包含3个线程的定时任务线程池ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);// 延迟2秒后执行一次任务executor.schedule(() -> {System.out.println("Delayed task executed");}, 2, TimeUnit.SECONDS);// 延迟1秒后,每3秒执行一次任务executor.scheduleAtFixedRate(() -> {System.out.println("Periodic task executed");}, 1, 3, TimeUnit.SECONDS);}
}

特点:核心线程数固定,最大线程数为Integer.MAX_VALUE。

支持两种调度方式:
schedule():延迟执行一次任务。
scheduleAtFixedRate()/scheduleWithFixedDelay():周期性执行任务。 

        总结:Executors 提供的工厂方法能快速创建线程池,但需根据实际场景谨慎选择。对于生产环境,建议手动配置线程池参数,避免使用默认的无界队列和无限线程数,以防止系统资源耗尽和内存溢出。 

http://www.dtcms.com/a/266060.html

相关文章:

  • SpringSecurity01
  • 【libm】 7 双精度正弦函数 (k_sin.rs)
  • 从混沌到澄明,AI如何重构我们的决策地图与未来图景
  • 把大象塞进冰箱总共分几步:讲讲dockerfile里conda的移植
  • IOC容器讲解以及Spring依赖注入最佳实践全解析
  • XILINX FPGA如何做时序分析和时序优化?
  • Linux之Socket编程Tcp
  • 【BurpSuite 2025最新版插件开发】基础篇7:数据的持久化存储
  • snail-job的oracle sql(oracle 11g)
  • 百度捂紧“钱袋子”
  • 冒泡排序及其优化方式
  • Javaweb - 10.1 Servlet
  • 两个手机都用同个wifi,IP地址会一样吗?如何更改ip地址
  • Redis实战:数据安全与性能保障
  • linux测试端口是否可被外部访问
  • ROS三维环境建模——基于OctoMap库
  • c++ 的标准库 --- std::
  • 【25-cv-07436】Keith律所代理《Four Season - Winter Breeze》画作维权!
  • NFSv4 ACL配置与参数
  • ubuntu防火墙使用
  • 【ChatTTS】ChatTTS使用体验
  • 关于系统无法找到 arm-linux-gcc 命令,这表明你的环境中尚未安装 ARM 交叉编译工具链。以下是详细的解决方案:(DIY机器人工房)
  • 通过HBA卡新增外接存储,详细流程
  • R 语言安装使用教程
  • Oracle面试题-体系结构
  • 《dlib库中的聚类》算法详解:从原理到实践
  • ABP VNext + Cosmos DB Change Feed:搭建实时数据变更流服务
  • 计算机科学导论(10)什么是BIOS
  • 探秘展销编辑器:相较于传统展销的卓越优势与甄选指南​
  • 按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具