对象池 commons-pool2


title: 对象池 commons-pool2
date: 2021-08-01 13:48:21
tags:

  • Java
  • 池化技术

1 前言

池化技术是性能调优的重要措施,池化的思想是把对象放到池子里面,当要使用的时候从池子里面拿对象,用完之后在放回池子里面。这样可以降低资源分配和释放资源的开销,从而提升性能。

在实际的项目中,我们每天都会接触到池化技术,例如:

  • 对象池:通过复用对象,减少对象创建、垃圾回收的开销
  • 线程池:通过复用线程来提升性能
  • 连接池:如数据库连接池、Redis连接池、HTTP连接池,通过复用TCP连接来减少创建和释放连接的时间来提升性能

2 对象池 - 适用场景

  • 维护一些很大、创建很慢的的对象来提升性能
  • 缺点:有学习成本、增加了代码复杂度

3 commons-pool2

  • Apache 基金会开源的对象池框架
  • 官网:https://commons.apache.org/proper/commons-pool/
  • Github:https://github.com/apache/commons-pool

commons-pool2 提供了两种对象池:

3.1 ObjectPool 接口

ObjectPool 是一个接口

3.1.1 实现类介绍

实现类 作用
BaseObjectPool 抽象类,用来扩展自己的对象池
ErodingObjectPool “腐蚀”对象池,代理一个对象池,并基于factor参数,为其添加“腐蚀”行为。归还的对象被腐蚀后,将会丢弃,而不是添加到空闲容量中。
GenericObjectPool 一个可配置的通用对象池实现
ProxiedObjectPool 代理一个其它的对象池,并基于动态代理(支持JDK代理和Cglib代理),返回一个代理后的对象。该对象池主要用来增强对池化对象的控制,比如防止在归还该对象后,还继续使用该对象等行为。
SoftReferenceObjectPool 基于软引用的对象池
SynchroizedObjectPool 代理一个其它的对象池,并为其提供线程安全的能力

3.1.2 核心API

方法名 作用
borrowObject() 从对象池借对象
returnObject() 将对象归还到对象池
invalidateObject() 失效一个对象
addObject() 增加一个空闲对象,该方法适用于使用空闲对象预加载对象池
clear() 清空空闲的所有对象,并释放相关资源
close() 关闭对象池,并释放相关资源
getNumIdIe() 获得空闲的对象数量
getNumActive() 获得被借出对象数量

3.2 KeyedObjectPool

它和ObejectPool的区别在于它是通过 Key 来找对象的。从设计上的角度看,KeyedObjectPool 和 ObjectPool 没有多少区别,它有以下实现类:

实现类 作用
ErodingKeyedObjectPool 类似ErodingObjectPool
GenericKeyedObjectPool 类似GenericObjectPool
ProxiedKeyedObjectPool 类似ProxiedObjectPool
SynchroizedKeyedObjectPool 类似SynchroizedObjectPool

3.2.1 PooledObjectFactory

实现类 作用
BasePooledObjectFactory 抽象类,用于扩展自己的PooledObjectFactory
PoolUtils.SynchronizedPooledObjectFactory 内部类,代理一个其它的PooledObjectFactory,实现线程同步,用 PoolUtils.synchronizedPooledFactory()创建

3.2.2 PooledObjectFactory 核心API

方案名 作用
makeObject 创建一个对象实例,并将其包装成一个PooledObject
destroyObject 销毁对象
validateObject 校验对象,确保对象池返回的对象是OK的
activeObject 重新初始化对象
passivated 取消初始化对象。GenriObjectPool 的 addIdIeObject、returnObject、evict调用该方法

3.2.3 PooledObject

实现类 作用
DefaultPooledObject 包装原始对象,实现监控(例如创建时间、使用时间等)、状态跟踪等
PooledSoftReferenceObject 进一步封装了DefaultPooledObject,用来和SoftReferenceObjectPool配置使用

PooledObject状态

对象池 commons-pool2

对象池 commons-pool2

3.2.2 示例代码

# 对象
public class Money {
  public static Money init() {
    // 假设对象new非常耗时
    try {
      Thread.sleep(10L);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return new Money("USD", new BigDecimal("1"));
  }

  private String type;
  private BigDecimal amount;

  public Money(String type, BigDecimal amount) {
    try {
      Thread.sleep(100L);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    this.type = type;
    this.amount = amount;
  }

  // 省略 getter,setter
}

# 对象池工厂类
public class MoneyPooledObjectFactory
  implements PooledObjectFactory<Money> {
  public static final Logger LOGGER =
    LoggerFactory.getLogger(MoneyPooledObjectFactory.class);

  @Override
  public PooledObject<Money> makeObject() throws Exception {
    DefaultPooledObject<Money> object = new DefaultPooledObject<>(
      new Money("USD", new BigDecimal("1"))
    );
    LOGGER.info("makeObject..state = {}", object.getState());
    return object;
  }

  @Override
  public void destroyObject(PooledObject<Money> p) throws Exception {
    LOGGER.info("destroyObject..state = {}", p.getState());
  }

  @Override
  public boolean validateObject(PooledObject<Money> p) {
    LOGGER.info("validateObject..state = {}", p.getState());
    return true;
  }

  @Override
  public void activateObject(PooledObject<Money> p) throws Exception {
    LOGGER.info("activateObject..state = {}", p.getState());
  }

  @Override
  public void passivateObject(PooledObject<Money> p) throws Exception {
    LOGGER.info("passivateObject..state = {}", p.getState());
  }
}

# 测试类
public class CommonsPool2Test {
  public static void main(String[] args) throws Exception {
    GenericObjectPool<Money> pool = new GenericObjectPool<>(new MoneyPooledObjectFactory());
    Money money = pool.borrowObject();
    money.setType("RMB");
    pool.returnObject(money);
  }
}

# 测试结果
  
makeObject..state = IDLE
activateObject..state = ALLOCATED
passivateObject..state = RETURNING

3.3 commons-pool2 总结

  • ObjectPool:对象池

    • 最核心:GenericObjectPool、GenericKeyedObjectPool
  • Factory:创建和管理 PooledObject

    • 一般要自己扩展
  • PooledObject:包装原有的对象,从而让对象池管理

    • 一般用 DefaultPooledObject

只要掌握这三点,一般就没有问题了

上一篇:More comprehensive War package dependencies


下一篇:05-SpringCloud 工程重构