自定义对象池BasePooledObjectFactory的使用

项目中用到了apache的对象池来管理文件导出相关资源连接和回收功能,因此花点时间简单了解下对象池相关使用,做点记录。

一. 连接池

频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定数量的连接,每次访问只需从连接池里获取连接,使用完毕后再放回连接池,并不是直接关闭连接,这样可以保证程序重复使用同一个连接而不需要每次访问都建立和关闭连接, 从而提高系统性能。

二、场景

场景
1,资源受限的, 不需要可伸缩性的环境(cpu\内存等物理资源有限): cpu性能不够强劲, 内存比较紧张, 垃圾收集, 内存抖动会造成比较大的影响, 需要提高内存管理效率, 响应性比吞吐量更为重要;
2,数量受限的, 比如数据库连接;
3,创建成本高的对象, 可以考虑是否池化, 比较常见的有线程池(ThreadPoolExecutor), 字节数组池等。

三、自定义对象池

1 引入依赖

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

2 定义Person对象

public class Person {private final String name;public Person(String name) {this.name = name;}public void create() {System.out.println("ThreadName:" + Thread.currentThread().getName() + " 对象:" + name + "正在被创建。。。。。。");}public void destroy() {System.out.println("ThreadName:" + Thread.currentThread().getName() + " 对象:" + name + "正在被销毁。。。。。。");}public boolean isValid() {System.out.println("ThreadName:" + Thread.currentThread().getName() + " 对象" + name + "正在检验是否可用。。。。。。");return true;}
}

3 对象池

public enum MyCommonPool {/*** 线程安全的单例*/INSTANCE;private final GenericObjectPool<Person> objectPool;MyCommonPool() {// 创建对象池配置GenericObjectPoolConfig<Person> poolConfig = new GenericObjectPoolConfig<>();// 对象池中最大对象数poolConfig.setMaxTotal(3);// 对象池中最小空闲对象数poolConfig.setMinIdle(1);// 对象池中最大空闲对象数poolConfig.setMaxIdle(2);// 当对象池耗尽时,是否等待获取对象poolConfig.setBlockWhenExhausted(true);// 创建对象时是否进行对象有效性检查poolConfig.setTestOnCreate(true);// 借出对象时是否进行对象有效性检查poolConfig.setTestOnBorrow(true);// 归还对象时是否进行对象有效性检查poolConfig.setTestOnReturn(true);// 空闲时是否进行对象有效性检查poolConfig.setTestWhileIdle(true);// 获取对象最大等待时间 默认 -1 一直等待poolConfig.setMaxWait(Duration.ofSeconds(2));// 创建对象工厂PersonBasePooledObjectFactory objectFactory = new PersonBasePooledObjectFactory();// 创建对象池objectPool = new GenericObjectPool<>(objectFactory, poolConfig);}/*** 从对象池中借出一个对象** @return Person* @throws Exception*/public Person borrowObject() throws Exception {Person zou = objectPool.borrowObject();int numActive = objectPool.getNumActive();int numIdle = objectPool.getNumIdle();System.out.println("ThreadName:" + Thread.currentThread().getName() + " 活跃对象数量:" + numActive + " 空闲对象数量:" + numIdle);System.out.println("------------------------------------------------------------");return zou;}public void returnObject(Person myObject) {// 将对象归还给对象池objectPool.returnObject(myObject);}/*** 获取活跃的对象数** @return int*/public int getNumActive() {return objectPool.getNumActive();}/*** 获取空闲的对象数** @return int*/public int getNumIdle() {return objectPool.getNumIdle();}
}

4 自定义线程池对象工厂

public class PersonBasePooledObjectFactory extends BasePooledObjectFactory<Person> {@Overridepublic Person create() {// 创建一个新的MyObject对象Person myObject = new Person(UUID.randomUUID().toString());myObject.create();return myObject;}@Overridepublic PooledObject<Person> wrap(Person myObject) {// 将MyObject对象封装到一个PooledObject对象中并返回return new DefaultPooledObject<>(myObject);}@Overridepublic void destroyObject(PooledObject<Person> pooledObject) {// 销毁对象Person myObject = pooledObject.getObject();myObject.destroy();}@Overridepublic boolean validateObject(PooledObject<Person> pooledObject) {// 验证对象是否可用Person myObject = pooledObject.getObject();return myObject.isValid();}
}

四、测试验证

1 对象池测试类

@SpringBootTest
public class PersonPoolTest {// 测试对象数使用情况@Testpublic void singleTest() throws Exception {// 最大对象数量3 最小空闲对象数量1 最大空闲数量 2MyCommonPool myObjectPool = MyCommonPool.INSTANCE;numActiveAndNumIdle(myObjectPool);// 获取对象Person obj = myObjectPool.borrowObject();// 获取对象Person obj2 = myObjectPool.borrowObject();// 获取对象Person obj3 = myObjectPool.borrowObject();// 第4次获取对象,已超出最大对象数3,则会抛出异常,线程终止//Person obj4 = myObjectPool.borrowObject();// 归还一次对象,则活跃对象-1,空闲对象+1myObjectPool.returnObject(obj);System.out.println("ThreadName:" + Thread.currentThread().getName()+ " returned: " + JSONObject.toJSONString(obj));numActiveAndNumIdle(myObjectPool);}/*** 活跃对象数和空闲对象数** @param myObjectPool 自定义对象池*/private static void numActiveAndNumIdle(MyCommonPool myObjectPool) {int numActive = myObjectPool.getNumActive();int numIdle = myObjectPool.getNumIdle();System.out.println("ThreadName:" + Thread.currentThread().getName()+ " 活跃对象数量:" + numActive + " 空闲对象数:" + numIdle);System.out.println("------------------------------------------------------------");}
}

2,当注释掉

Person obj4 = myObjectPool.borrowObject();

会根据自定义对象池参数:最大对象数量3 最小空闲对象数量1 最大空闲数量 2输出结果
在这里插入图片描述
当放开

Person obj4 = myObjectPool.borrowObject();

第4次获取对象,已超出最大对象数3,则会抛出异常,线程终止
在这里插入图片描述
源码下载 demo-springboot-mybatisplus,欢迎Star!

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

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

相关文章

C++ | Leetcode C++题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();int buy1 -prices[0], sell1 0;int buy2 -prices[0], sell2 0;for (int i 1; i < n; i) {buy1 max(buy1, -prices[i]);sell1 max(…

OceanBase v4.2 特性解析:新增三种临时表功能,更多的Oracle语句兼容

特性说明 在Oracle模式下&#xff0c;OceanBase临时表已经实现了基本的create、select、insert、delete、update等功能。为了满足更多客户的需求&#xff0c;OceanBase正在扩展临时表的功能&#xff0c;例如支持merge into和insert all操作。merge into允许用户将源表中的数据…

FPGA高端项目:FPGA解码MIPI视频+图像缩放+视频拼接,基于MIPI CSI-2 RX Subsystem架构实现,提供4套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我这里已有的 MIPI 编解码方案本方案在Xilinx Artix7-35T上解码MIPI视频的应用本方案在Xilinx Artix7-100T上解码MIPI视频的应用本方案在Xilinx Kintex7上解码MIPI视频的应用本方案在Xilinx Zynq7000上解码MIPI视频的应用本方案在…

Linux基础命令目录管理002

之前讲述了目录的创建和删除&#xff0c;现在讲一下目录的移动修改。 操作系统&#xff1a; CentOS Stream 9 操作命令&#xff1a; mv 移动&#xff0c;重命名 选项 -v显示移动过程 [rootlocalhost ~]# mkdir 12 [rootlocalhost ~]# ll 总用量 1220 drwxr-xr-x 2 root…

11.1 排序算法

目录 11.1 排序算法 11.1.1 评价维度 11.1.2 理想排序算法 11.1 排序算法 排序算法&#xff08;sorting algorithm&#xff09;用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 如图 1…

WebSocket实现前后端双向数据的实时推送

一、WebSocket简介 WebSocket是一种网络通信协议&#xff0c;旨在实现客户端和服务器之间的双向、全双工通信。它在HTML5规范中被引入&#xff0c;用于替代基于传统HTTP协议的长轮询、轮询和流传输等方式&#xff0c;以提供更高效的实时数据传输。 WebSocket的特点 双向通信&a…

Python 3 判断文件是否存在

1 使用os.path模块 import osfile_path hello.txtif os.path.exists(file_path):print(f"文件 {file_path} 存在。") else:print(f"文件 {file_path} 不存在。") 2 使用pathlib模块 from pathlib import Pathfile_path Path(word.txt)if file_path.ex…

32-ESP32-S3-WIFI篇-03 Event Loop (事件循环)

ESP32-S3-WIFI 事件循环 介绍 在ESP32-S3的WiFi驱动程序中&#xff0c;事件循环是一个非常重要的概念。事件循环是一个无限循环&#xff0c;用于处理和分发系统中发生的各种事件。在WiFi驱动程序中&#xff0c;我们使用事件循环来处理和分发WiFi相关的事件。 创建事件循环 …

PTA 7-10 构造二叉检索树

本题目构造一棵二叉检索树。要求读入n个整数&#xff0c;以0结束。最后输出这棵树的先序序列。 输入格式: 输入n个整数&#xff0c;以0表示结束&#xff0c;数据间以空格隔开。 输出格式: 输出这棵树的先序序列&#xff0c;以一个空格隔开&#xff0c;结尾也有一个空格。 …

常用电机测试方法的介绍与功能实现(M测试方法)

目录 概述 1 常用电机测速方法简介 1.1 方法概览 1.2 编码器测速方法 2 M法测速 2.1 理论描述 2.2 实现原理 2.3 速度计算方法 3 功能实现 3.1 功能介绍 3.2 代码实现 3.2.1 使用STM32Cube配置参数 3.2.2 脉冲计数功能 3.2.3 测速函数 4 测试 概述 本文主要介绍…

springboot针对返回的response拦截处理越权问题

背景&#xff1a;针对越权测试&#xff0c;通过拦截工具Fiddler修改请求参数&#xff0c;越权查看平台里面所有公司的数据 1、自定义MyResponseBodyAdvice 实现ResponseBodyAdvice 使用过滤器和拦截我都试过&#xff0c;最终没有成功&#xff0c;可能技术比较菜&#xff0c;这…

策略模式解析

import java.util.*; enum TYPE { NORMAL,CASH_DISCOUNT,CASH_RETURN}; interface Cashsuper { public double acceptCash(double money); } class CashNormal implements CashSuper{// 正常收费子类 public double accptCash(double money){ return money; …

C# Winform 已知窗体句柄,如何遍历出所有控件句柄

c# windform 已知窗体句柄&#xff0c;如何遍历出所有控件句柄 public delegate bool CallBack(int hwnd, int lParam);public delegate bool EnumWindowsProc(int hWnd, int lParam); List<string> list new List<string>();[DllImport("user32.dll")]…

通过MySQL JSON函数实现对GSON字段属性的搜索和筛选

在 MySQL 中直接对 Gson 格式的字段进行搜索是有一定的限制的&#xff0c;因为 MySQL 不支持直接解析和操作 JSON 或 Gson 数据。不过你可以使用一些函数来模拟实现对 Gson 字段内部某个属性的搜索&#xff0c;比如使用 LIKE 来做模糊匹配。 假设你的表名为 gson_table&#x…

GPT-4o版本间的对比分析和使用心得

GPT-4o&#xff1a;对人工智能领域的新贡献 GPT-4o是OpenAI最新发布的语言模型&#xff0c;相比于其前身GPT-4和更早的版本GPT-3&#xff0c;具有显著的改进和增强。以下是对GPT-4o的详细评价&#xff0c;包括版本间的对比分析、技术能力的提升&#xff0c;以及我在实际使用过…

黑马一站制造数仓实战2

问题 DG连接问题 原理&#xff1a;JDBC&#xff1a;用Java代码连接数据库 Hive/SparkSQL&#xff1a;端口有区别 可以为同一个端口&#xff0c;只要不在同一台机器 项目&#xff1a;一台机器 HiveServer&#xff1a;10000 hiveserver.port 10000 SparkSQL&#xff1a;10001…

谈谈Android AOP技术方案

先统一一下基本名词&#xff0c;以便表述。 切面&#xff1a;对一类行为的抽象&#xff0c;是切点的集合&#xff0c;比如在用户访问所有模块前做的权限认证。 切点&#xff1a;描述切面的具体的一个业务场景。 通知&#xff08;Advice&#xff09;类型&#xff1a;通常分为切…

一维时间序列信号的广义傅里叶族变换(Matlab)

广义傅里叶族变换是一种时频变换方法&#xff0c;傅里叶变换、短时傅里叶变换、S变换和许多小波变换都是其特殊情况&#xff0c;完整代码及子函数如下&#xff0c;很容易读懂&#xff1a; % Run a demo by creating a signal, transforming it, and plotting the results% Cre…

不同厂商SOC芯片在视频记录仪领域的应用

不同SoC公司芯片在不同产品上的应用信息&#xff1a; 大唐半导体 芯片型号: LC1860C (主控) LC1160 (PMU)产品应用: 红米2A (399元)大疆晓Spark技术规格: 28nm工艺&#xff0c;4个ARM Cortex-A7处理器&#xff0c;1.5GHz主频&#xff0c;2核MaliT628 GPU&#xff0c;1300万像…

计算属性与监听属性

【 1 】计算属性 计算属性大致就是这样 # 1 计算属性是基于它们的依赖进行缓存的# 2 计算属性只有在它的相关依赖发生改变时才会重新求值# 3 计算属性就像Python中的property&#xff0c;可以把方法/函数伪装成属性 # 计算属性本质上是一个函数&#xff0c;它们可以通过 get…