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

池化技术、Commons Pool介绍

概述

池化技术,一种通过重复利用对象实例而非频繁创建和销毁的技术。

常见的可池化对象:

  • 数据库连接(Connection):数据库连接创建和销毁代价高,连接池广泛用于管理JDBC连接;
  • 线程(Thread):线程的创建和销毁开销大,线程池是多线程编程中常用的技术;
  • 网络连接(Socket/HTTPClient):复用HTTP连接以提高网络通信效率;
  • 对象实例(Object):对于短生命周期且频繁使用的对象,可通过对象池管理其生命周期;
  • 内存块或缓冲区(Buffer):I/O操作中经常使用缓冲池(如Netty的ByteBuf池)来减少内存分配和垃圾回收的开销;
  • 会话或上下文对象(Session/Context):在Web应用或分布式系统中,Session对象可通过池化优化访问性能。

具体的池化技术:

  • 数据库连接池:如HikariCP、Druid、C3P0;管理JDBC连接生命周期,包括创建、复用和回收。
  • 线程池:如Java中的ExecutorService和ThreadPoolExecutor。控制线程的并发量和资源使用,避免频繁创建线程。
  • HTTP连接池:如OkHttp、Apache HttpClient。复用HTTP连接,减少TCP连接开销。
  • 对象池:如Apache Commons Pool、HikariCP的对象池管理。用于频繁创建和销毁的轻量级对象实例。
  • 缓冲区池:如Netty的内存池(ByteBufAllocator),池化I/O缓冲区以减少垃圾回收的负担。
  • GPU内存池:如CUDA的内存池,在深度学习或图像处理场景中复用显存资源。
  • 分布式对象池:如Redisson对Redis资源的池化封装,管理分布式系统中的共享资源。

当遇到以下场景,可考虑使用池化技术来提高系统性能:

  • 对象的创建或销毁很频繁,需要使用较多的系统资源,如数据库连接、线程、HTTP请求;
  • 生命周期较短且重复使用的对象,如临时计算对象、缓冲区;
  • 需要高并发和低延迟,如Web服务、实时数据流处理;
  • 资源昂贵的操作,如GPU显存管理、大型文件处理。

优势

  • 减少资源开销:通过复用降低对象的创建和销毁成本;
  • 提高性能:更快的响应时间和更少的垃圾回收;
  • 降低复杂度:池化工具通常内置优化策略(如负载均衡、超时管理)。

注意事项

  • 资源竞争:池的大小配置过小可能导致资源争抢,过大则浪费资源;
  • 池中对象管理:需要避免对象泄漏或资源未正确释放;
  • 过期资源处理:池化资源可能因为网络或连接原因失效,需实现健康检查和自动回收。

线程池

参考面试必备之线程池(Java),以及ForkJoinPool,以及MySQL线程池。

连接池

参考JDBC与数据库连接池。

缓冲池

MySQL提供缓冲池能力,待学习。

对象池

提到对象池,不得不说ApacheGitHub的Commons Pool。

官方文档

核心组件(API):

  • 对象池(ObjectPool):实现对对象存取和状态管理的池实现,如:线程池、数据库连接池;
  • 池化对象(PooledObject):池化对象,放在ObjectPool里的包装类。添加一些附加信息,如状态,创建时间,激活时间,关闭时间等;
  • 池化对象工厂(PooledObjectFactory):工厂类,负责具体对象的创建、初始化、销毁和状态验证。

关系图
在这里插入图片描述

实战

引入如下依赖:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.12.0</version>
</dependency>

实现一个简单的数据库连接池:

@AllArgsConstructor
public class DatabaseConnectionFactory extends BasePooledObjectFactory<Connection> {private String connectionString;private String username;private String password;// 创建新的数据库连接@Overridepublic Connection create() {try {return DriverManager.getConnection(connectionString, username, password);} catch (SQLException e) {throw new RuntimeException("创建数据库连接失败", e);}}// 销毁数据库连接@Overridepublic void destroyObject(PooledObject<Connection> p) throws Exception {p.getObject().close();}// 验证数据库连接是否有效@Overridepublic boolean validateObject(PooledObject<Connection> p) {try {return p.getObject().isValid(1); // 设置一个非常短的超时,仅用于检查连接是否仍然可用} catch (SQLException e) {return false;}}// 激活对象,可选,No-op@Overridepublic void activateObject(PooledObject<Connection> p) throws Exception {// 可在这里进行一些连接重新激活的操作,例如设置自动提交、隔离级别等}// 钝化对象,可选,No-op@Overridepublic void passivateObject(PooledObject<Connection> p) throws Exception {// 可在对象返回到池之前执行一些清理或重置操作}
}

配置和创建ObjectPool:

public class DatabaseConnectionPool {private static GenericObjectPool<Connection> pool;static {// 配置连接池的参数GenericObjectPoolConfig config = new GenericObjectPoolConfig();config.setMaxTotal(10); // 设置连接池的最大连接数config.setMaxIdle(5); // 设置连接池的最大空闲连接数config.setMinIdle(2); // 设置连接池的最小空闲连接数DatabaseConnectionFactory factory = new DatabaseConnectionFactory("jdbc:mysql://localhost:3306/mydatabase", "user", "password");// 初始化连接池pool = new GenericObjectPool<>(factory, config);}// 获取数据库连接public static Connection getConnection() throws Exception {return pool.borrowObject();}// 归还数据库连接到池public static void releaseConnection(Connection conn) {if (conn != null) {pool.returnObject(conn);}}// 关闭连接池(通常在应用程序关闭时调用)public static void close() {if (pool != null) {pool.close();}}
}

最后是测试类:

public static void main(String[] args) {try (Connection conn = DatabaseConnectionPool.getConnection()) {// 使用连接执行数据库操作        // 连接会在try-with-resources块结束时自动归还到池中} catch (Exception e) {// log}// 注意:在应用程序结束时,应该调用DatabaseConnectionPool.close()来关闭连接池
}

原理

大致如下图
在这里插入图片描述
注:

  • minEvictableldleTimeMillis是早期版本的拼写,最新版2.12.0对应的参数是minEvictableIdleDuration;
  • softMinEvictableldleTimeMillis对应的参数是softMinEvictableIdleDuration;
  • timeBetweenEvictionRunsMillis对应的参数是durationBetweenEvictionRuns。

4个test参数:

  • testOnCreate:指定在创建时,是否对池化对象进行有效性检测;以下类似
  • testOnBorrow:获取
  • testOnReturn:归还
  • testWhileIdle:空闲检测

生产环境,建议只将testWhileIdle设置为true,其他几个参数设置为false,并通过调整空闲检测时间间隔(timeBetweenEvictionRunsMillis,durationBetweenEvictionRuns)来保证资源的可用性和效率。

源码

ObjectPool:

public interface ObjectPool<T> extends Closeable {// 添加对象void addObject() throws Exception;// 添加多个对象default void addObjects(final int count) throws Exception {for (int i = 0; i < count; i++) {addObject();}}// 从池中获取对象T borrowObject() throws Exception;// 清除池,池可用void clear() throws Exception;// 关闭池,池不可用@Overridevoid close();// 获取活跃对象个数int getNumActive();// 获取空闲对象个数int getNumIdle();// 废弃对象void invalidateObject(T obj) throws Exception;// 使用指定的废弃模式废弃对象default void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception {invalidateObject(obj);}// 将对象放回池中void returnObject(T obj) throws Exception;
}

枚举类DestroyMode源码如下:

public enum DestroyMode {// 常规废弃NORMAL,// Destroy abandoned objectABANDONED
}

PooledObject:

public interface PooledObject<T> extends Comparable<PooledObject<T>> {static boolean isNull(final PooledObject<?> pooledObject) {return pooledObject == null || pooledObject.getObject() == null;}boolean allocate();boolean deallocate();boolean endEvictionTest(Deque<PooledObject<T>> idleQueue);default Duration getActiveDuration() {// Take copies to avoid threading issuesfinal Instant lastReturnInstant = getLastReturnInstant();final Instant lastBorrowInstant = getLastBorrowInstant();// @formatter:offreturn lastReturnInstant.isAfter(lastBorrowInstant) ?Duration.between(lastBorrowInstant, lastReturnInstant) :Duration.between(lastBorrowInstant, Instant.now());// @formatter:on}@Deprecateddefault Duration getActiveTime() {return getActiveDuration();}@Deprecatedlong getActiveTimeMillis();default long getBorrowedCount() {return -1;}default Instant getCreateInstant() {return Instant.ofEpochMilli(getCreateTime());}@Deprecatedlong getCreateTime();default Duration getFullDuration() {return Duration.between(getCreateInstant(), Instant.now());}default Duration getIdleDuration() {return Duration.ofMillis(getIdleTimeMillis());}@Deprecateddefault Duration getIdleTime() {return Duration.ofMillis(getIdleTimeMillis());}@Deprecatedlong getIdleTimeMillis();default Instant getLastBorrowInstant() {return Instant.ofEpochMilli(getLastBorrowTime());}@Deprecatedlong getLastBorrowTime();default Instant getLastReturnInstant() {return Instant.ofEpochMilli(getLastReturnTime());}@Deprecatedlong getLastReturnTime();default Instant getLastUsedInstant() {return Instant.ofEpochMilli(getLastUsedTime());}@Deprecatedlong getLastUsedTime();T getObject();PooledObjectState getState();void invalidate();void markAbandoned();void markReturning();void printStackTrace(PrintWriter writer);void setLogAbandoned(boolean logAbandoned);default void setRequireFullStackTrace(final boolean requireFullStackTrace) {// noop}boolean startEvictionTest();void use();@Overrideint compareTo(PooledObject<T> other);@Overrideboolean equals(Object obj);	@Overrideint hashCode();String toString();
}

PooledObjectFactory,泛型接口:

public interface PooledObjectFactory<T> {void activateObject(PooledObject<T> p) throws Exception;void destroyObject(PooledObject<T> p) throws Exception;default void destroyObject(final PooledObject<T> p, final DestroyMode destroyMode) throws Exception {destroyObject(p);}PooledObject<T> makeObject() throws Exception;void passivateObject(PooledObject<T> p) throws Exception;boolean validateObject(PooledObject<T> p);
}

解读:

  • makeObject:创建一个新对象;当对象池中的对象个数不足(个数配置,参考下面的Config)时,将会使用此方法来产生一个新的对象,并交付给对象池管理;
  • destroyObject:销毁对象,如果检测到对象池中某个对象idle的时间超时,或操作者向对象池归还对象时检测到对象已经无效,则触发对象销毁。调用此方法时,对象的生命周期必须结束。如果object是线程,则线程必须退出;如果是Socket操作,则Socket必须关闭;如果是文件流操作,则此时数据flush且正常关闭。
  • validateObject:检测对象是否有效;Pool中不能保存无效的对象,因此后台检测线程会周期性的检测Pool中对象的有效性,如果对象无效则会导致此对象从Pool中移除,并destroy;此外在调用者从Pool获取一个对象时,也会检测对象的有效性,确保不会将无效的对象输出给调用者;当调用者使用完毕将对象归还到Pool时,仍然会检测对象的有效性。有效性,就是此对象的状态是否符合预期,调用者是否可直接使用;如果对象是Socket,有效性则意味着Socket的通道是否畅通/阻塞是否超时等。
  • activateObject:激活对象,当Pool中决定移除一个对象交付给调用者时额外的激活操作,比如可在activateObject方法中重置参数列表让调用者使用时感觉像一个新创建的对象一样。如果object是线程,可在激活操作中重置线程中断标记,或让线程从阻塞中唤醒等;如果是Socket,则可在激活操作中刷新通道,或对Socket进行连接重建(假如Socket意外关闭)等。
  • passivateObject:钝化对象,当调用者归还对象时,Pool将会钝化对象。如果object是Socket,则清除buffer,将Socket阻塞;如果是线程,可在钝化操作中将线程sleep或将线程中的某个对象wait。activateObject和passivateObject两个方法需要一一对应,避免死锁或对象状态的混乱。

BaseObjectPoolConfig提供的配置:

  • lifo:连接池放池化对象方式,默认为true
  • true:放在空闲队列最前面
  • false:放在空闲队列最后面
  • fairness:等待线程拿空闲连接的方式,默认为false
  • true:相当于等待线程是在先进先出去拿空闲连接
  • maxWaitMillis:当连接池资源耗尽时,调用者最大阻塞的时间,超时将抛出异常。单位为毫秒数;默认为-1,表示永不超时。已废弃,请使用maxWaitDuration
  • minEvictableIdleTimeMillis:连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除;默认值1000L 60L 30L。已废弃,请使用minEvictableIdleDuration
  • softMinEvictableIdleTimeMillis:连接空闲的最小时间,达到此值后空闲连接将会被移除,且保留minIdle个空闲连接数。已废弃,请使用softMinEvictableIdleDuration
  • numTestsPerEvictionRun:对于空闲连接检测线程而言,每次检测的连接资源的个数。默认值3
  • evictionPolicyClassName:默认值org.apache.commons.pool2.impl.DefaultEvictionPolicy
  • testOnCreate:默认值false
  • testOnBorrow:向调用者输出连接资源时,是否检测是有有效,如果无效则从连接池中移除,并尝试获取继续获取。默认为false。建议保持默认值
  • testOnReturn:默认值false
  • testWhileIdle:向调用者输出连接对象时,是否检测它的空闲超时;默认为false。如果连接空闲超时,将会被移除;建议保持默认值。默认值false
  • timeBetweenEvictionRunsMillis:空闲连接检测线程,检测周期,单位是毫秒数。如果为负值,表示不运行检测线程。默认值为-1。已废弃,请使用durationBetweenEvictionRuns
  • durationBetweenEvictionRuns:
  • blockWhenExhausted:默认值true
  • jmxEnabled:默认值true
  • jmxNamePrefix:默认值pool
  • jmxNameBase:默认值null
  • maxTotal:连接池中最大连接数

参考

http://www.lryc.cn/news/491288.html

相关文章:

  • 下载并安装Visual Studio 2017过程
  • 菊风视频能力平台开发服务正式入驻华为云云商店,成为华为云联营联运合作伙伴
  • springboot整合kafka
  • Python深度学习框架:PyTorch、Keras、Scikit-learn、TensorFlow如何使用?学会轻松玩转AI!
  • 【Linux】安装cuda
  • 为什么DDoS防御很贵?
  • 将WPS的PPT 无损的用微软的PowerPoint打开
  • 【汇编】uniapp开发
  • 详解Oracle表的类型(二)
  • Docker--通过Docker容器创建一个Web服务器
  • Next.js-样式处理
  • 整合Springboot shiro jpa mysql 实现权限管理系统(附源码地址)
  • 极智嘉嵌入式面试题及参考答案
  • 【MySQL】数据库核心技术与应用指南
  • 23省赛区块链应用与维护(房屋租凭)
  • 深度学习4
  • 跳绳视觉计数方案
  • TEA加密逆向
  • LeetCode 404.左叶子之和
  • 01-go入门
  • 【经典】抽奖系统(HTML,CSS、JS)
  • GoF设计模式——结构型设计模式分析与应用
  • Java后端如何进行文件上传和下载 —— 本地版
  • json格式数据集转换成yolo的txt格式数据集
  • 什么是Three.js,有什么特点
  • Linux笔记--基于OCRmyPDF将扫描件PDF转换为可搜索的PDF
  • Unity 导出 Xcode 工程 修改 Podfile 文件
  • UE5 slate BlankProgram独立程序系列
  • 内存不足引发C++程序闪退崩溃问题的分析与总结
  • C++ —— 以真我之名 如飞花般绚丽 - 智能指针