项目中用到了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!