深入理解Apache Commons Pool2池化技术

在这里插入图片描述

码到三十五 : 个人主页

心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 !


在现代软件开发中,为了提高性能和资源利用率,开发者们经常使用池化技术来管理那些创建和销毁代价较高的对象,比如数据库连接、网络套接字或线程。Apache Commons Pool2是Apache基金会提供的一个优秀的对象池化库,它为开发者提供了一套丰富的API和灵活的配置选项,以实现对象的池化管理。

目录

    • 1️⃣Apache Commons Pool2简介
    • 2️⃣为什么要使用对象池
    • 3️⃣Apache Commons Pool2的工作原理
      • 3.1. 对象池(ObjectPool)
      • 3.2. 池化对象(PooledObject)
      • 3.3. 对象工厂(PooledObjectFactory)
    • 4️⃣对象的取用和回收
      • 4.1 对象的取用(Borrowing)
      • 4.2 对象的回收(Returning)
    • 5️⃣pache Commons Pool2实现数据库连接池
    • 6️⃣ Apache Commons Pool2的使用场景
      • 6.1. 数据库连接池
      • 6.2. HTTP连接池
      • 6.3. 线程池
      • 6.4. 其他需要复用对象的场景
    • 7️⃣结语

1️⃣Apache Commons Pool2简介

Apache Commons Pool2是Apache Commons下的一个开源项目,主要用于实现和管理对象池。对象池是一种常见的设计模式,通过复用来分摊昂贵对象的创建和销毁代价,从而优化资源利用和提高应用程序性能。

Commons Pool2提供了一套用于实现对象池化的API,并内置了多种各具特色的对象池实现。其被广泛应用在各种数据库连接池、线程池以及请求分发池中。其实现提供了一些参数来控制对象池的行为,例如最大池化对象数、最大空闲时间、最小空闲数等,可以根据不同的应用场景进行灵活配置。

此外,Commons Pool2也提供了一些常用的实现类,如GenericObjectPool,它实现了一个功能强大的对象池,可以方便地进行配置和扩展。通过使用Commons Pool2,开发者可以更加轻松地实现和管理对象池,提高应用程序的性能和可靠性。

2️⃣为什么要使用对象池

  1. 资源复用:对象池通过复用对象实例,避免了频繁创建和销毁对象带来的开销。这对于创建和销毁成本较高的对象(如数据库连接、线程、复杂的数据结构等)尤为有益。

  2. 性能提升:由于减少了对象的创建和销毁次数,应用程序的响应时间得以改善,整体性能得到提升。对象池可以确保在需要时快速提供可用对象,减少了等待时间。

  3. 降低垃圾收集压力:频繁的对象创建和销毁会增加垃圾收集器的工作负担,可能导致应用程序的停顿和延迟。对象池通过减少不必要的对象分配和释放,降低了垃圾收集的频率和强度,从而提高了应用程序的稳定性。

  4. 可预测性和可控性:对象池允许开发者对池中的对象数量进行控制和调整,以满足应用程序的需求。通过配置池的大小、最大空闲时间等参数,可以实现对资源使用的精细控制,提高系统的可预测性和可控性。

  5. 简化资源管理:对象池封装了对象的创建、验证、销毁等复杂逻辑,使得开发者可以更加专注于业务逻辑的实现,而无需过多关注底层的资源管理细节。

总之,对象池是一种有效的资源管理技术,可以帮助开发者提高应用程序的性能、稳定性和可维护性。然而,需要注意的是,对象池并不适用于所有场景。在决定是否使用对象池时,需要综合考虑对象的创建和销毁成本、资源消耗情况、并发需求等因素。

3️⃣Apache Commons Pool2的工作原理

Commons Pool2提供了一套用于实现对象池化的API,并内置了多种各具特色的对象池实现。其中,核心的接口是ObjectPool,它定义了对象池应该实现的行为,包括对象的取用(borrow)、回收(return)和其他管理操作。同时,PooledObject是对池中对象的封装,包含对象的状态和一些其他信息。PooledObjectFactory是一个工厂类,负责具体对象的创建、初始化、状态销毁和验证等工作。
在这里插入图片描述

其工作原理主要基于以上三个核心概念:对象池(ObjectPool)、池化对象(PooledObject)和对象工厂(PooledObjectFactory)。

3.1. 对象池(ObjectPool)

  • 定义了对象池应该实现的行为,包括对象的取用(borrow)、回收(return)和其他管理操作。
  • 对象池负责存储和管理所有池化对象。它内部维护了一个队列,用于存储空闲对象,并在需要时提供对象,当对象不再使用时将其回收。
  • 对象池还提供了一系列的配置参数,比如最大池化对象数、最小空闲对象数、最大等待时间等,这些参数可以帮助开发者根据应用场景来细粒度地调整对象池的行为。

3.2. 池化对象(PooledObject)

  • 池化对象是对实际对象的包装。它除了持有实际对象的引用外,还包含了一些元数据,比如对象的状态(空闲、使用中、待销毁等)、创建时间、最后使用时间等。
  • 当一个实际对象被包装成池化对象并加入到对象池中时,它的生命周期就交由对象池来管理。只有当对象池决定销毁该对象时,实际对象的生命周期才会结束。

3.3. 对象工厂(PooledObjectFactory)

  • 对象工厂负责创建和销毁池化对象。它提供了create()、destroy()和validate()等方法。
  • 当对象池需要一个新的对象时,它会调用对象工厂的create()方法来创建一个新的对象,并将其包装成池化对象后加入到对象池中。
  • 当对象池中的一个对象不再需要使用时,对象池会调用对象工厂的destroy()方法来销毁该对象。但在销毁之前,对象池会先调用validate()方法来检查该对象是否仍然可用。如果validate()方法返回false,则对象池会立即销毁该对象;否则,它会将该对象标记为空闲状态并放回到对象池中等待下次使用。

4️⃣对象的取用和回收

Apache Commons Pool2 对象池提供了对象的创建、验证、取用(borrowing)、回收(returning)和销毁等功能。对象池的主要目的是复用对象,以减少对象创建和销毁的开销。
以下是 Apache Commons Pool2 中对象的取用和回收逻辑:

4.1 对象的取用(Borrowing)

  1. 请求对象:当客户端需要从对象池中获取一个对象时,它会调用 ObjectPool.borrowObject() 方法。

  2. 检查空闲对象:池首先会检查是否有可用的空闲对象。这通常是通过查看一个内部队列或集合来实现的,该队列或集合维护着当前未被使用的对象。

  3. 验证对象:如果找到了一个空闲对象,池通常会使用 PooledObjectFactory.validateObject() 方法来验证该对象是否仍然有效。如果对象无效,它将被销毁,并且池会尝试获取另一个对象。

  4. 创建新对象(如果需要):如果没有可用的空闲对象,或者所有空闲对象都已失效,池将使用 PooledObjectFactory.create() 方法来创建一个新对象。如果创建失败(例如,由于资源限制或配置问题),则可能会抛出异常。

  5. 返回对象给客户端:一旦验证或创建了一个有效对象,它就会被返回给客户端以供使用。此时,该对象被视为“被借出”的状态。

4.2 对象的回收(Returning)

  1. 归还对象:当客户端完成对象的使用后,它应该调用 ObjectPool.returnObject() 方法来将对象归还给池。这是确保对象能够被其他客户端复用的重要步骤。

  2. 验证对象:与取用过程类似,归还的对象也会通过 PooledObjectFactory.validateObject() 方法进行验证。如果验证失败,对象将被销毁而不是放回池中。

  3. 放回空闲队列:如果对象验证成功,它将被放回池的空闲队列中,等待下一个客户端的请求。

  4. 处理过剩对象:在某些情况下,当池中的空闲对象数量超过配置的最大空闲数时,池可能会选择销毁一些对象以减少资源占用。这通常是通过 PooledObjectFactory.destroyObject() 方法来实现的。

  5. 资源清理:除了验证和放回对象外,归还过程还可能包括一些额外的资源清理步骤,如关闭数据库连接、释放网络资源等。这些步骤通常是在 PooledObjectFactory 的实现中定义的。

通过管理对象的生命周期和复用,Apache Commons Pool2 能够帮助应用程序提高性能并减少资源消耗。然而,正确配置和使用对象池是至关重要的,以避免出现资源泄漏、性能瓶颈或其他问题。

5️⃣pache Commons Pool2实现数据库连接池

下面代码使用Apache Commons Pool2实现一个简单的数据库连接池。这个示例将展示如何创建一个自定义的PooledObjectFactory来管理数据库连接,并配置和使用ObjectPool来复用这些连接。

首先,我们需要一个PooledObjectFactory实现,用于创建、验证和销毁数据库连接:

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class DatabaseConnectionFactory extends BasePooledObjectFactory<Connection> {private String connectionString;private String username;private String password;public DatabaseConnectionFactory(String connectionString, String username, String password) {this.connectionString = connectionString;this.username = username;this.password = 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;}}// 激活对象(可选实现,这里我们什么也不做)@Overridepublic void activateObject(PooledObject<Connection> p) throws Exception {// 可以在这里进行一些连接重新激活的操作,例如设置自动提交、隔离级别等}// 钝化对象(可选实现,这里我们什么也不做)@Overridepublic void passivateObject(PooledObject<Connection> p) throws Exception {// 可以在对象返回到池之前执行一些清理或重置操作}
}

接下来,我们需要配置和创建ObjectPool

import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;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 class Application {public static void main(String[] args) {// 从连接池中获取连接try (Connection conn = DatabaseConnectionPool.getConnection()) {// 使用连接执行数据库操作// ...// 连接会在try-with-resources块结束时自动归还到池中} catch (Exception e) {// 处理异常e.printStackTrace();}// 注意:在应用程序结束时,应该调用DatabaseConnectionPool.close()来关闭连接池。}
}

在上面的示例中,DatabaseConnectionFactory类负责创建、验证和销毁数据库连接,而DatabaseConnectionPool类则负责配置和管理连接池。应用程序通过调用DatabaseConnectionPool.getConnection()来获取连接,并在使用完毕后通过DatabaseConnectionPool.releaseConnection(conn)来归还连接到池中。使用try-with-resources语句可以确保连接在使用完毕后被正确关闭并归还到池中,即使在执行数据库操作时发生异常也是如此。

这个示例演示了Apache Commons Pool2在实际应用程序中的一个典型用法,即通过对象池化管理来复用昂贵的资源,从而提高应用程序的性能和效率。

6️⃣ Apache Commons Pool2的使用场景

Apache Commons Pool2由于其高效的对象管理能力和灵活的配置选项,在多种场景中得到了广泛应用:

6.1. 数据库连接池

  • 在Web应用程序或后台服务中,经常需要频繁地与数据库进行交互。如果每次交互都创建一个新的数据库连接并在使用后立即销毁它,那么这将造成大量的资源浪费和时间开销。通过使用Apache Commons Pool2来实现数据库连接池,可以复用数据库连接对象,显著提高应用程序的性能和吞吐量。

6.2. HTTP连接池

  • 在处理大量HTTP请求时,为每个请求创建一个新的HTTP连接也是不划算的。通过使用Apache Commons Pool2来管理HTTP连接对象,可以避免频繁地建立和关闭连接所带来的开销,提高系统的并发处理能力。

6.3. 线程池

  • 线程是操作系统中的昂贵资源之一。频繁地创建和销毁线程会导致系统性能下降甚至崩溃。通过使用Apache Commons Pool2来实现线程池,可以复用已经创建的线程对象来处理任务队列中的任务,从而降低线程创建和销毁的开销,提高系统的稳定性和响应速度。

6.4. 其他需要复用对象的场景

  • 除了上述常见的应用场景外,Apache Commons Pool2还可以应用于其他任何需要复用对象的场景中,比如文件句柄池、套接字连接池等。只要对象的创建和销毁代价较高且需要频繁使用,就可以考虑使用Apache Commons Pool2来实现对象池化管理。

7️⃣结语

总的来说,Commons Pool2是一个成熟、稳定且易于使用的对象池化框架,它能够帮助开发者提高应用程序的性能和可靠性,降低资源消耗和垃圾收集的压力。无论是数据库连接池、线程池还是其他类型的对象池,Commons Pool2都是一个值得考虑的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/741663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode108题:将有序数组转换为二叉搜索树(python3)

一个容易想到的思路&#xff1a;使用 nums 中最靠近中心的位置作为整棵 BST 的根节点&#xff0c;确保左右子树节点数量平衡。随后递归构造 nums 中下标范围为 [0,mid−1]作为左子树&#xff0c;递归构造 nums 中下标范围为 [mid1,n−1]作为右子树。 # Definition for a binar…

I2C学习总结

i2c概述 I2C&#xff08;Inter-Intergreted Circuit&#xff09; 是一种串行通信协议&#xff0c;用于集成电路之间完成数据传输&#xff0c;i2c用广泛用以各种领域&#xff0c;包括电子设备、嵌入式系统、工业自动化等&#xff1b; i2c仅仅只是一个数据传输的协议&#xff0c…

逻辑斯特 + 神经网络梯度下降公式推导 + 向量化

全部推导来自吴恩达老师的视频课&#xff0c;下面仅作整理 逻辑斯特 神经网络

Vue+OpenLayers7入门到实战:使用webgl图层叠加超大量Point点要素,解决叠加超过一百万数据量点位导致浏览器卡住变慢的问题

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 本章介绍如何使用OpenLayers7在解决地图上叠加超过几千以上要素点就开始变慢,一万以上的要素点的时候,浏览器页面就开始卡顿或直接卡死,甚至浏览器会弹出是否等待页面加载的提示。 这时候要怎么优化?OpenLayers官…

win10安装Ubuntu22.04LTS及深度学习相关配置详细教学

由于之前Ubuntu系统硬盘空间分配的不够&#xff0c;又去看了一下发现扩容很很麻烦。加以发现自己前面安装的深度学习环境版本与实际要用的不符&#xff0c;所以当机立断决定直接重装系统。 Ubuntu系统安装 参考视频&#xff1a;一看就会&#xff01;8分钟真机安装【Ubuntu/Wi…

JWT原理

JWT 介绍 JWT&#xff08;JSON Web Token&#xff09;是一个开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种简洁的、自包含的方法用于通信双方之间以 JSON 对象的形式安全地传输信息。这种信息可以被验证和信任&#xff0c;因为它是数字签名的。JWT通常用于…

第二证券|沪指窄幅震荡跌0.26%,半导体概念走强,保险板块跌幅居前

13日早盘&#xff0c;沪深两市窄幅震动&#xff0c;三大指数均小幅跌落。盘面上&#xff0c;人工智能方向团体反弹&#xff0c;半导体个股走势活跃。 到午间收盘&#xff0c;沪指跌0.26%&#xff0c;报3047.85点&#xff1b;深成指跌0.15%&#xff0c;报9615.92点&#xff1b;…

ruoyi-vue插件集成websocket

链接&#xff1a;插件集成 | RuoYi WebSocketServer.java&#xff1a;补充代码 /*** 此为广播消息* param message 消息内容*/public void sendAllMessage(String message) {LOGGER.info("【websocket.sendAllMessage】广播消息:"message);try {for(String sessionI…

300分钟吃透分布式缓存-27讲:Redis是如何进行主从复制的?

Redis 复制原理 为了避免单点故障&#xff0c;数据存储需要进行多副本构建。同时由于 Redis 的核心操作是单线程模型的&#xff0c;单个 Redis 实例能处理的请求 TPS 有限。因此 Redis 自面世起&#xff0c;基本就提供了复制功能&#xff0c;而且对复制策略不断进行优化。 通…

基于SWOT的智能手机企业财务战略研究1.62

摘 要 近些年&#xff0c;网络技术日新月异&#xff0c;智能手机深受消费者喜爱&#xff0c;人们通过网络&#xff0c;手机应用&#xff0c;可以极大地方便人们学习&#xff0c;工作等等。由于国家对电信行业的大力支持&#xff0c;中国消费者群体逐步成为最具潜力的手机购买者…

十六、接口隔离原则、反射、依赖注入

接口隔离原则、反射、特性、依赖注入 接口隔离原则 客户端不应该依赖它不需要的接口&#xff1b;一个类对另一个类的依赖应该建立在最小的接口上。 五种原则当中的i 上一章中的接口&#xff0c;即契约。 契约就是在说两件事&#xff0c;甲方说自己不会多要&#xff0c;乙方会在…

朴素贝叶斯算法基础——案例:对新闻进行分类

贝叶斯公式 朴素&#xff1a;假设特征与特征之间相互独立 朴素贝叶斯算法&#xff1a;朴素贝叶斯 应用场景&#xff1a;文本分类&#xff08;单词作为特征&#xff09; 拉普拉斯平滑系数 Ni&#xff1a;F1词在C类别所有文档中出现的次数 N&#xff1a;所属类别C下的文档所…

AHU 数据库 实验三

《数据库》实验报告 【实验名称】 实验3 数据库的连接查询 【实验目的】 1. 熟悉基本的连接查询的概念和作用&#xff1b; 2. 了解数据库管理系统DBMS 实现连接查询的基本方法&#xff1b; 3. 掌握SQL语言连接查询语句的语法和功能&#…

STM32第十课:串口发送

一、usart串口 1.1 USART串口协议 串口通讯(Serial Communication) 是一种设备间非常常用的串行通讯方式&#xff0c;因为它简单便捷&#xff0c;因此大部分电子设备都支持该通讯方式&#xff0c;电子工程师在调试设备时也经常使用该通讯方式输出调试信息。在计算机科学里&…

主流数据库的区别

几个主流的数据库有&#xff1a; 1. MySQL&#xff1a;MySQL是一种关系型数据库管理系统&#xff0c;常用于Web应用程序开发和数据存储。 2. Oracle&#xff1a;Oracle是一种关系型数据库管理系统&#xff0c;由Oracle Corporation开发和销售。它广泛用于企业级应用程序中。 …

在使用qml的qmldir文件创建常用组件报错unknow component

解决方法&#xff1a;Qt Creator中的工具-->QML/JS-->重置代码模型 参考博文:QML自定义模块及qmldir的使用_同一资源文件目录下的qml模块使用-CSDN博客 不一样的地方是我给我的文件起了别名 以及我的qrc文件路径有前缀/qml 总体操作&#xff1a; 1.使用模块中的组件时…

线程与进程的区别、协程

1【线程与进程的区别、协程】 【1】 进程跟线程 进程&#xff08;Process&#xff09;和 线程&#xff08;Thread&#xff09;是操作系统的基本概念&#xff0c; 但是它们比较抽象&#xff0c; 不容易掌握。关于多进程和多线程&#xff0c;教科书上对经典的一句话“进程是资源分…

铭文:探索比特币世界的数字印记

铭文是什么&#xff1f; 铭文指的是在某种物品&#xff08;如石头、硬币、平板等&#xff09;上刻有文字。在比特币领域&#xff0c;铭文指的是刻在聪&#xff08;satoshi&#xff09;上的元数据。比特币的最小单位是聪&#xff0c;1比特币可分为1亿聪。每个聪都通过序数理论进…

OpenAI GPT LLMs 高级提示词工程方法汇总

原文地址&#xff1a;An Introduction to Prompt Engineering for OpenAI GPT LLMs Github&#xff1a;Prompt-Engineering-Intro 2023 年 3 月 2 日 提示工程指南 | Prompt Engineering Guide Naive 提示词&#xff1a;带有提示的情感分类器 prompt Decide whether a T…

计算机缺失iutils.dll怎么办,分享5种靠谱的解决方法

​在计算机系统运行过程中&#xff0c;如果发现无法找到或缺失iutils.dll文件&#xff0c;可能会引发一系列的问题与故障。首先&#xff0c;由于iutils.dll是系统中一个重要的动态链接库文件&#xff0c;它的主要功能可能涉及到系统核心服务、应用程序支持或者特定功能模块的运…