Apache Commons Pool2 池化技术

对象池是一种设计模式,用于管理和重用对象,以提高性能和资源利用率。对象池的概念在许多应用程序中都有广泛应用,特别是在需要频繁创建和销毁对象的情况下,例如数据库连接、线程、HTTP连接等

对象池通过预先创建一组对象并将它们存储在池中,以供需要时获取和使用。当对象不再需要时,它们不会被销毁,而是被返回到池中,以便在后续的请求中重新使用

对象池的优点包括:

  • 减少对象创建和销毁的开销,提高性能和响应时间
  • 最大限度地利用系统资源,避免资源的浪费
  • 控制对象的数量,防止资源耗尽和系统崩溃
  • 提供对象的重用机制,避免频繁的对象创建和垃圾回收

Apache Commons Pool2

Apache Commons Pool2 是一个广泛使用的Java对象池库,被许多开源项目和企业应用程序采用。它提供了通用的对象池化解决方案,可用于管理各种类型的对象,如数据库连接、线程池、HTTP连接等

Commons Pool 工作原理

核心类

ObjectPool

对象池,负责对对象进行生命周期的管理,并提供了对对象池中活跃对象和空闲对象统计的功能

  • 对象的提供与归还:borrowObjectreturnObject
  • 创建对象:addObject
  • 销毁对象:invalidateObject
  • 池中空闲对象数量、被使用对象数量:getNumActivegetNumIdle

PooledObjectFactory

对象工厂类,负责具体对象的创建、初始化,对象状态的销毁和验证

commons-pool2框架本身提供了默认的抽象实现BasePooledObjectFactory,业务方在使用的时候只需要继承该类,然后实现warpcreate方法即可

PooledObject

池化对象,是需要放到ObjectPool对象的一个包装类。添加了一些附加的信息,比如说状态信息,创建时间,激活时间等

池对象状态及流程

PooledObjectState 池对象状态枚举

public enum PooledObjectState {//在空闲队列中,还未被使用IDLE,//使用中ALLOCATED,//在空闲队列中,当前正在测试是否满足被驱逐的条件EVICTION,//不在空闲队列中,目前正在测试是否可能被驱逐。因为在测试过程中,试图借用对象,并将其从队列中删除。//回收测试完成后,它应该被返回到队列的头部。EVICTION_RETURN_TO_HEAD,//在队列中,正在被校验VALIDATION,//不在队列中,当前正在验证。该对象在验证时被借用,由于配置了testOnBorrow,//所以将其从队列中删除并预先分配。一旦验证完成,就应该分配它。VALIDATION_PREALLOCATED,//不在队列中,当前正在验证。在之前测试是否将该对象从队列中移除时,曾尝试借用该对象。//一旦验证完成,它应该被返回到队列的头部。VALIDATION_RETURN_TO_HEAD,//无效状态(如驱逐测试或验证),并将/已被销毁INVALID,//判定为无效,将会被设置为废弃ABANDONED,//正在使用完毕,返回池中RETURNING
}

流程理解

此段原文自 https://www.cnblogs.com/haixiang/p/14783955.html

对象存储
 private PooledObject<T> create() throws Exception {.....final PooledObject<T> p;try {p = factory.makeObject();.....allObjects.put(new IdentityWrapper<>(p.getObject()), p);return p;}

我们查看allObjects,所有对象都存储于ConcurrentHashMap,除了被杀掉的对象

/** All of the objects currently associated with this pool in any state. It* excludes objects that have been destroyed. The size of* {@link #allObjects} will always be less than or equal to {@link* #_maxActive}. Map keys are pooled objects, values are the PooledObject* wrappers used internally by the pool.*/
private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =new ConcurrentHashMap<>();
对象取用逻辑
  • 首先根据AbandonedConfig配置判断是否取用对象前执行清理操作
  • 再从idleObject中尝试获取对象,获取不到就创建新的对象
    • 判断blockWhenExhausted是否设置为true,是的话按照设置的borrowMaxWaitMillis属性等待可用对象(这个配置的意思是当对象池的active状态的对象数量已经达到最大值maxinum时是否进行阻塞直到有空闲对象)
  • 有可用对象后调用工厂的factory.activateObject方法激活对象
  • getTestOnBorrow设置为true时,调用factory.validateObject(p)对对象进行校验,通过校验后执行下一步
  • 调用updateStatsBorrow方法,在对象被成功借出后更新一些统计项,例如返回对象池的对象个数等

//....
private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
//....
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {assertOpen();final AbandonedConfig ac = this.abandonedConfig;if (ac != null && ac.getRemoveAbandonedOnBorrow() &&(getNumIdle() < 2) &&(getNumActive() > getMaxTotal() - 3) ) {removeAbandoned(ac);}PooledObject<T> p = null;// Get local copy of current config so it is consistent for entire// method executionfinal boolean blockWhenExhausted = getBlockWhenExhausted();boolean create;final long waitTime = System.currentTimeMillis();while (p == null) {create = false;p = idleObjects.pollFirst();if (p == null) {p = create();if (p != null) {create = true;}}if (blockWhenExhausted) {if (p == null) {if (borrowMaxWaitMillis < 0) {p = idleObjects.takeFirst();} else {p = idleObjects.pollFirst(borrowMaxWaitMillis,TimeUnit.MILLISECONDS);}}if (p == null) {throw new NoSuchElementException("Timeout waiting for idle object");}} else {if (p == null) {throw new NoSuchElementException("Pool exhausted");}}if (!p.allocate()) {p = null;}if (p != null) {try {factory.activateObject(p);} catch (final Exception e) {try {destroy(p, DestroyMode.NORMAL);} catch (final Exception e1) {// Ignore - activation failure is more important}p = null;if (create) {final NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");nsee.initCause(e);throw nsee;}}if (p != null && getTestOnBorrow()) {boolean validate = false;Throwable validationThrowable = null;try {validate = factory.validateObject(p);} catch (final Throwable t) {PoolUtils.checkRethrow(t);validationThrowable = t;}if (!validate) {try {destroy(p, DestroyMode.NORMAL);destroyedByBorrowValidationCount.incrementAndGet();} catch (final Exception e) {// Ignore - validation failure is more important}p = null;if (create) {final NoSuchElementException nsee = new NoSuchElementException("Unable to validate object");nsee.initCause(validationThrowable);throw nsee;}}}}}updateStatsBorrow(p, System.currentTimeMillis() - waitTime);return p.getObject();}
对象的激活和钝化

在对象使用完被返回对象池时,如果校验失败直接销毁,如果校验通过需要先钝化对象passivateObject(PooledObject<T> p)再存入空闲队列。至于激活对象的方法activateObject(PooledObject<T> p)在上述取用对象时也会先激活再被取出。因此我们可以发现处于空闲和使用中的对象他们除了状态不一致,我们也可以通过激活和钝化的方式在他们之间增加新的差异

例如我们要做一个Elasticsearch连接池,每个对象就是一个带有ip和端口的连接实例,很显然访问es集群是多个不同的ip,所以每次访问的ip不一定相同,我们则可以在激活操作为对象赋值ip和端口,钝化操作中将ip和端口归为默认值或者空,这样流程更为标准

对象回收机制

EvictionTimer为回收对象的定时器,当且仅当设置了timeBetweenEvictionRunsMillis参数后才会开启定时清理任务

对象状态为evict,直接调用destroy进行回收。否则会进行进一步地处理,逻辑如下:

  1. 尝试激活对象,如果激活失败则认为对象已经不再存活,直接调用destroy进行销毁
  2. 在激活对象成功的情况下,会通过validateObject方法取校验对象状态,如果校验失败,则说明对象不可用,需要进行销毁
// org.apache.commons.pool2.impl.GenericObjectPool#evict
if (evict) {destroy(underTest);destroyedByEvictorCount.incrementAndGet();
} else {if (testWhileIdle) {boolean active = false;try {factory.activateObject(underTest);active = true;} catch (Exception e) {destroy(underTest);destroyedByEvictorCount.incrementAndGet();}if (active) {if (!factory.validateObject(underTest)) {destroy(underTest);destroyedByEvictorCount.incrementAndGet();} else {try {factory.passivateObject(underTest);} catch (Exception e) {destroy(underTest);destroyedByEvictorCount.incrementAndGet();}}}}if (!underTest.endEvictionTest(idleObjects)) {// TODO - May need to add code here once additional// states are used}
}

常用参数详解

参数类型(默认值)描述
lifoboolean(true)当去获取对象池中的空闲实例时,是否需要遵循后进先出的原则
fairnessboolean(false)当对象池处于exhausted状态,即可用实例为空时,大量线程在同时阻塞等待获取可用的实例,fairness配置来控制是否启用公平锁算法,即先到先得。这一项的前提是blockWhenExhausted配置为true
maxTotalint(8)对象池中最大使用数量
maxIdleint(8)对象中空闲对象最大数量
minIdleint(0)对象池中空闲对象最小数量
maxWaitMillislong(-1)最大阻塞时间,当对象池处于exhausted状态,即可用实例为空时,大量线程在同时阻塞等待获取可用的实例,如果阻塞时间超过了maxWaitMillis将会抛出异常
testOnCreateboolean(false)创建对象前,是否校验该新对象的有效性
testOnBorrowboolean(false)取用对象前,是否检验对象的有效性
testOnReturnboolean(false)归还对象前,是否检验对象的有效性
testWhileIdleboolean(false)当回收器在扫描空闲对象时,是否校验对象的有效性
numTestsPerEvictionRunint(3)根据该值x可以推导出一个数值n,标识回收过程需要检查多少个空闲对象。如果x>=0,那么n=x。如果x<0,那么n=(空闲对象数量/x的绝对值)向上取整,假设空闲对象一共有10个,该值配置为-3,那么就意味着这次回收需要检查4个空闲对象
timeBetweenEvictionRunsMillislong(-1)回收器线程多久执行一次空闲对象回收
softMinEvictableIdleTimeMillislong(-1)软回收时间阈值一个对象如果空闲时间超过了该值(毫秒),并且空闲对象的数量已经大于了minIdle时,就可以被回收器回收
minEvictableIdleTimeMillislong(1000L * 60L * 30L)硬回收时间阈值一个对象如果空闲时间超过了该值,即使空闲对象的数量已经小于minIdle了,一样也会被回收器回收

假如在某个高负载的系统里,对象频繁被借出、被归还。此时推荐对象池配置为

  1. testOnBorrowtestOnReturn都设置为false,提升性能
  2. timeBetweenEvictionRunsMillis设置为60000,一分钟进行一次空闲对象的回收检查
  3. numTestsPerEvictionRun设置为-1,检查所有空闲对象
  4. minEvictableIdleTimeMillis设置为180000,空闲超过3分钟的可以被回收
  5. testWhileIdle设置为true,不管空闲时间是否超时,每个空闲对象都检查下有效性,无效的一样被回收

通过异步的回收器来尽可能的保证空闲对象的有效性,减少同步调用时有效性检查导致的响应延迟、以及有效性检查对底层带来的访问压力

总结

Apache Commons Pool2是一个用于对象池化的Java库,它提供了一种管理和重用对象实例的机制,旨在改善应用程序的性能和资源利用率。下面是对Apache Commons Pool2的总结:

  • 对象池化:Apache Commons Pool2允许您创建和管理一个对象池,该对象池中保存着可重用的对象实例。通过将对象保存在池中而不是频繁地创建和销毁对象,可以减少系统开销,提高性能。
  • 对象生命周期管理:Pool2提供了生命周期管理功能,允许您定义在对象从池中借出和归还时的初始化和清理操作。这确保了从池中借出的对象始终处于一种可用状态。
  • 池化策略:Pool2支持多种池化策略,如通用对象池、软引用对象池和弱引用对象池。您可以根据应用程序的需求选择适合的策略。
  • 线程安全:Pool2是线程安全的,它提供了同步机制来处理多个线程同时访问池的情况,确保对象的正确分配和归还。
  • 配置灵活:Pool2允许您通过配置文件或编程方式来配置对象池的各种属性,如最大池大小、最小空闲对象数、池中对象的最大空闲时间等。这使得您可以根据应用程序的需求进行优化和调整。
  • 连接池和资源池:Pool2不仅适用于对象池,还可用于连接池和其他资源的池化管理。这使得它在处理数据库连接、线程池等资源时非常有用。

总的来说,Apache Commons Pool2是一个功能强大且灵活的对象池化库,可帮助您管理和重用对象实例,提高应用程序的性能和资源利用率。无论是在Web应用程序、并发编程还是资源管理方面,Pool2都是一个可靠的选择


参考资料:

  1. Apache Commons Pool
  2. commons-pool2 池化技术探究
  3. 对象池
  4. apache common pool2原理与实战

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

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

相关文章

B. Comparison String

题目&#xff1a; 样例&#xff1a; 输入 4 4 <<>> 4 >><< 5 >>>>> 7 <><><><输出 3 3 6 2 思路&#xff1a; 由题意&#xff0c;条件是 又因为要使用尽可能少的数字&#xff0c;这是一道贪心题&#xff0c;所以…

最大内切圆算法计算裂缝宽度

本文这里是对CSDN上另一位博主的代码进行了整理&#xff1a; 基于opencv的裂缝宽度检测算法&#xff08;计算轮廓最大内切圆算法&#xff09; 我觉得这位博主应该是上传了一个代码草稿&#xff0c;我对其进行了重新整理&#xff0c;并添加了详细的注释。 import cv2 import …

ICCV 2023|Occ2Net,一种基于3D 占据估计的有效且稳健的带有遮挡区域的图像匹配方法...

本文为大家介绍一篇入选ICCV 2023的论文&#xff0c;《Occ2Net: Robust Image Matching Based on 3D Occupancy Estimation for Occluded Regions》&#xff0c; 一种基于3D 占据估计的有效且稳健的带有遮挡区域的图像匹配方法。 论文链接&#xff1a;https://arxiv.org/abs/23…

[红明谷CTF 2021]write_shell %09绕过过滤空格 ``执行

目录 1.正常短标签 2.短标签配合内联执行 看看代码 <?php error_reporting(0); highlight_file(__FILE__); function check($input){if(preg_match("/| |_|php|;|~|\\^|\\|eval|{|}/i",$input)){ 过滤了 木马类型的东西// if(preg_match("/| |_||php/&quo…

Java应用生产Full GC或者OOM问题如何定位

1 引言 生产应用服务频繁Full GC却无法释放内存&#xff0c;甚至可能OOM&#xff0c;这种情况很有可能是内存泄露或者堆内存分配不足&#xff0c;此时需要dump堆信息来定位问题&#xff0c;查看是哪些地方内存泄漏。 Dump文件也称为内存转储文件或内存快照文件&#xff0c;是…

【Axure】常见元件、常用交互效果

产品结构图 以微信为例&#xff0c;根据页面层级制作 动态面板 动态面板的作用&#xff1a;动态面板是一个可视区域&#xff0c;如果要把控件放进去&#xff0c;要全部放进去&#xff0c;放多少显示多少 文本框 隐藏边框方法&#xff1a;先拉一个矩形&#xff0c;去掉部分…

基于Java的汽车票网上预订系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

在windows的ubuntu LTS中安装及使用EZ-InSAR进行InSAR数据处理

EZ-InSAR&#xff08;曾被称为MIESAR&#xff0c;即Matlab界面用于易于使用的合成孔径雷达干涉测量&#xff09;是一个用MATLAB编写的工具箱&#xff0c;用于通过易于使用的图形用户界面&#xff08;GUI&#xff09;进行干涉合成孔径雷达&#xff08;InSAR&#xff09;数据处理…

vue-cli项目打包体积太大,服务器网速也拉胯(100kb/s),客户打开网站需要等十几秒!!! 尝试cdn优化方案

一、首先用插件webpack-bundle-analyzer查看自己各个包的体积 插件用法参考之前博客 vue-cli项目中&#xff0c;使用webpack-bundle-analyzer进行模块分析&#xff0c;查看各个模块的体积&#xff0c;方便后期代码优化 二、发现有几个插件体积较大&#xff0c;有改成CDN引用的…

亚信科技AntDB数据库 高并发、低延迟、无死锁,深入了解AntDB-M元数据锁的实现

AntDB-M在架构上分为两层&#xff0c;服务层和存储引擎层。元数据的并发管理集中在服务层&#xff0c;数据的存储访问在存储引擎层。为了保证DDL操作与DML操作之间的一致性&#xff0c;引入了元数据锁&#xff08;MDL&#xff09;。 AntDB-M提供了丰富的元数据锁功能&#xff0…

【Axure高保真原型】3D圆柱图_中继器版

今天和大家分享3D圆柱图_中继器版的原型模板&#xff0c;图表在中继器表格里填写具体的数据&#xff0c;调整坐标系后&#xff0c;就可以根据表格数据自动生成对应高度的圆柱图&#xff0c;鼠标移入时&#xff0c;可以查看对应圆柱体的数据……具体效果可以打开下方原型地址体验…

一文带你搞懂Redis持久化

Redis持久化 Redis的数据是存储在内存的&#xff0c;当程序崩溃或者服务器宕机&#xff0c;那么内存里的数据就会丢失。所以避免数据丢失的情况&#xff0c;需要将数据保存到其他的存储设备中。 Redis提供两种方式来持久化&#xff0c;分别是 RDB(Redis Database)&#xff1a…

【LeetCode热题100】--19.删除链表的倒数第N个结点

19.删除链表的倒数第N个结点 注意&#xff1a;先声明一个头结点&#xff0c;它的next指针指向链表的头节点&#xff0c;这样就不需要对头节点进行特殊的判断 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListN…

【Java每日一题】——第十六题:将数组元素逆序并遍历输出。(2023.09.30)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第十五题。 &#x1f3af;问题&#xff1a; 设有数组如下&#xff1a;int[] arr{11,34,47,19,5,87,63,88}; 测试结果如下&#xff1a; &#x1f3af; 答案&#xff1a; int a[]new int [10];Random …

华为云HECS云服务器docker环境下安装nginx

前提&#xff1a;有一台华为云服务器。 华为云HECS云服务器&#xff0c;安装docker环境&#xff0c;查看如下文章。 华为云HECS安装docker-CSDN博客 一、拉取镜像 下载最新版Nginx镜像 (其实此命令就等同于 : docker pull nginx:latest ) docker pull nginx查看镜像 dock…

ai创作工具,怎么使用AI创作工具

不论是写一篇博客、发布自媒体、还是设计广告文案&#xff0c;创作都成为了我们日常生活和工作中不可或缺的一部分。但是&#xff0c;许多人可能会面临写作灵感枯竭、时间不足或需要大量内容的问题。 写作对于很多人来说&#xff0c;不仅是一项技能&#xff0c;更是一种挑战。有…

Spring学习笔记11 GoF代理模式

Spring学习笔记10 JdbcTemplate_biubiubiu0706的博客-CSDN博客 新建个maven模块 static-proxy 演示静态代理 订单接口 测试 需求:统计每个业务方法的耗时 package com.example.proxy.service;/*** author hrui* date 2023/9/25 8:42*/ public class OrderServiceImpl implem…

Linux CentOS7 vim临时文件

在vim中&#xff0c;由于断网、停电、故意退出、不小心关闭终端等多种原因&#xff0c;正在编辑的文件没有保存&#xff0c;系统将会为文件保存一个交换文件&#xff0c;或称临时文件&#xff0c;或备份文件。 如果因某种原因产生了交换文件&#xff0c;每次打开文件时&#x…

ffmpeg、ffplay在线安装,离线导出整个程序,移植到其他服务器使用(linux系统)

环境说明 以ubuntu系统作为说明 在线安装 下面命令会同时安装ffplay和ffmpeg sudo apt-get install ffmpeg怎么验证安装成功&#xff1f; 输入ffmpeg命令 ffmpeg&#xff0c;如图则说明安装成功 转储可执行程序和依赖的文件 找到安装路径&#xff0c;一般在/usr/bin目录…

idea Springboot 教师标识管理系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 教师标识管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统 具有完整的源代码和数据库&…