commons-pool2源码走读(四) 对象池实现GenericObjectPool<T>

commons-pool2源码走读(四) 对象池实现GenericObjectPool<T>

GenericObjectPool <T> 是一个可配置的ObjectPool实现。
当与适当的PooledObjectFactory组合使用时,GenericObjectPool为任意对象提供健壮的池功能。

您可以选择性的配置池来检查和可能回收池中的空闲对象,并确保有最少数量的空闲对象可用。这是由一个“空闲对象回收”线程(即BaseGenericObjectPool <T> 的Evictor)执行的,线程是异步运行的。在配置这个可选特性时,应该谨慎使用。驱逐运行与客户端线程争用池中的对象,因此如果它们运行得太频繁,可能会导致性能问题。

还可以配置池来检测和删除被泄漏的对象,比如一个从池中借出的对象,在超过removeAbandonedTimeout超时之前既不使用也不返回。移除泄漏的连接,可能发生在对象被借用时对象池已接近饱和,也可能是被回收线程检查出,或者两者都执行时。如果池对象实现了TrackedUse接口,那么其最后一次使用时间使取决于getLastUsed方法;否则,是由对象从池中借出的时间决定。

实现注意:为了防止可能的死锁,已经采取了谨慎措施,以确保在同步块中不会发生对工厂方法的调用。这个类线程安全。

1、接口继承、实现关系

GenericObjectPool <T> 实现了ObjectPool<T> 具备对象池的功能,同时 继承了BaseGenericObjectPool<T> 的对于对象状态管理和回收等功能。
这里写图片描述

2、构造函数

构造函数通过GenericObjectPoolConfig 和PooledObjectFactory来进行参数的初始化和对象工厂类的引入。

    public GenericObjectPool(final PooledObjectFactory<T> factory,
            final GenericObjectPoolConfig config) {
        //父类BaseGenericObjectPool构造方法
        super(config, ONAME_BASE, config.getJmxNamePrefix());

        if (factory == null) {
            jmxUnregister(); // tidy up
            throw new IllegalArgumentException("factory may not be null");
        }
        this.factory = factory;
        //空闲对象队列,此队列非JDK而是自行实现的一个队列
        idleObjects = new LinkedBlockingDeque<>(config.getFairness());
        //覆盖BaseGenericObjectPool里面的配置参数
        setConfig(config);
        //初始化回收线程
        startEvictor(getTimeBetweenEvictionRunsMillis());
    }

3、相关属性

    // --- 可配置的属性 -------------------------------------------------
    //最大空闲数量
    private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
    //最小空闲数量
    private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
    //对象工厂
    private final PooledObjectFactory<T> factory;

    // --- 内部属性 -------------------------------------------------

    //池中所有的对象,只能是<=maxActive
    private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
        new ConcurrentHashMap<>();
    //已创建对象总数(不包含已销毁的)
    private final AtomicLong createCount = new AtomicLong(0);
    //调用创建方法总线程数
    private long makeObjectCount = 0;
    //makeObjectCount 增长时并发锁
    private final Object makeObjectCountLock = new Object();
    //空闲对象队列
    private final LinkedBlockingDeque<PooledObject<T>> idleObjects;

    // JMX specific attributes
    private static final String ONAME_BASE =
        "org.apache.commons.pool2:type=GenericObjectPool,name=";

    //泄漏对象回收配置参数
    private volatile AbandonedConfig abandonedConfig = null;

4、 对象池方法实现

  • 借用对象
    整个流程为,检查池是否关闭 –> 是否回收泄漏对象 –> 是否阻塞创建对象 –> 创建对象 –> 分配对象 –> 激活对象 –> 校验对象 –> 更改借用信息 –> 返回对象
   public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
        //判断对象池是否关闭:BaseGenericObjectPool.closed==true
        assertOpen();
        //如果回收泄漏的参数配置不为空,并且removeAbandonedOnBorrow参数配置为true
        //并且Idle数量<2,Active数量>总数Total-3
        //在借用时进行回收泄漏连接(会影响性能)
        final AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
                (getNumIdle() < 2) &&
                (getNumActive() > getMaxTotal() - 3) ) {
            //回收泄漏对象
            removeAbandoned(ac);
        }

        PooledObject<T> p = null;

        //copy blockWhenExhausted 防止其它线程更改getBlockWhenExhausted值造成并发问题
        //借用对象时如果没有是否阻塞直到有对象产生
        final boolean blockWhenExhausted = getBlockWhenExhausted();
        //创建成功标识
        boolean create;
        //记录当前时间,用作记录借用操作总共花费的时间
        final long waitTime = System.currentTimeMillis();
        //当对象为空时一直获取
        while (p == null) {
            create = false;
            //从双端队列弹出第一个队首对象,为空返回null
            p = idleObjects.pollFirst();
            //如果为空则重新创建一个对象
            if (p == null) {
                //创建对象
                p = create();
                //p==null可能对象池达到上限不能继续创建!
                if (p != null) {
                    create = true;
                }
            }
            //如果对象p还是为空则阻塞等待
            if (blockWhenExhausted) {
                if (p == null) {
          
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值