commons pool2

commons pool2

前言

项目中使用到了微服务的框架thrift,服务间通过RPC通讯,每次RPC调用,都需要建立长连接,使用完成后关闭长连接,在高并发场景下,效率不高,这时,我们就需要采用池化技术,使用连接池,通过空间换时间,不必每次都创建和关闭连接,提高我们的RPC的调用效率。这里我们采用的是Apache的commons pool2,这时一个开源的对象池组件,使用较为广泛,我们常用的jedis就是使用它作为底层的对象池。

使用

commons pool2可以通过maven方式引入,也可以通过jar包的方式引入,具体根据项目情况定。
如何在项目中实际使用呢?需要以下3个步骤:

  1. 封装API,引用GenericObjectPool的接口
  2. 实现 PooledObjectFactory接口,实现对象的生成,校验和销毁
  3. 实现GenericObjectPoolConfig配置,我们采用的方式是继承GenericObjectPoolConfig,做好对象池的配置,包括对象池的大小,容量,空闲检测策略,借用和归还策略等

针对对象池的配置,这里列举几个关键配置:

  • maxTotal 对象池的容量
  • maxIdle 对象池最大的空闲对象数量
  • maxWaitMillis 获取对象的最大等待时间
  • testWhileIdle 是否开启空闲检测
  • minEvictableIdleTimeMillis 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除
  • timeBetweenEvictionRunsMillis 空闲连接,检测线程,检测的周期
  • numTestsPerEvictionRun 检测线程每次检测的对象数量
  • testOnBorrow 获取对象时是否校验对象有效性
  • testOnReturn 归还对象时是否校验对象有效性

commons pool2的关健类

GenericObjectPool是我们接下来会使用到的对象池底层的核心类,类图见下:
这里写图片描述
GenericObjectPool类里面函数较多,我们不一一列举,这里列出几个关健的函数,便于后续使用:
public T borrowObject(long borrowMaxWaitMillis) 获取对象
public void returnObject(T obj) 归还对象
public void invalidateObject(T obj) 发生异常归还的处理
public void close() 销毁对象池
public void evict() 空闲检测函数

borrowObject 借用对象

private final AtomicLong createCount = new AtomicLong(0); //创建对象的数量
private final LinkedBlockingDeque<PooledObject<T>> idleObjects;//空闲对象队列
   public T borrowObject(long borrowMaxWaitMillis) throws Exception {
        assertOpen();

        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 execution
        boolean blockWhenExhausted = getBlockWhenExhausted();

        boolean create;
        long waitTime = System.currentTimeMillis();
        //对象借用的核心流程
        while (p == null) {
            create = false;
            //资源耗尽是否阻塞,默认为true
            if (blockWhenExhausted) {
                //尝试从队列中获取对象,从头获取
                p = idleObjects.pollFirst();
                if (p == null) {
                    //获取失败,尝试创建对象
                    p = create();
                    if (p != null) {
                        create = true;
                    }
                }
                if (p == null) {
                    //如果创建对象失败,表明对象池已经达到了maxTotal,无法创建对象
                    //borrowMaxWaitMillis为获取对象最大等待时间,如果为-1,则从队列头尝试获取
                    if (borrowMaxWaitMillis < 0) {
                        p = idleObjects.takeFirst();
                    } else {
                        //从队列头获取,如果队列为空,则会阻塞等待borrowMaxWaitMillis
                        p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    }
                }
                //此时还没有获取到,表明没有人释放对象,等待超时,或者对端服务已经挂掉,抛出异常
                if (p == null) {
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                }
                //设置对象的状态,由IDLE设置为ALLOCATED,同时设置对象的属性,如lastBorrowTime,lastUseTime等
                if (!p.allocate()) {
                    p = null;
                }
            } else {
                //非阻塞的获取,大致流程一致,去除了阻塞等待部分
                p = idleObjects.pollFirst();
                if (p == null) {
                    p = create();
                    if (p != null) {
                        create = true;
                    }
                }
                if (p == null) {
                    throw new NoSuchElementException("Pool exhausted");
                }
                if (!p.allocate()) {
                    p = null;
                }
            }
            //对象获取成功,这时调用我们自己编写的factory对象,对对象做激活,校验
            if (p != null) {
                try {
                    //激活对象
                    factory.activateObject(p);
                } catch (Exception e) {
                    try {
                        destroy(p);
                    } catch (Exception e1) {
                        // Ignore - activation failure is more important
                    }
                    p = null;
                    if (create) {
                        NoSuchElementException nsee = new NoSuchElementException(
                                "Unable to activate object");
                        nsee.initCause(e);
                        throw nsee;
                    }
                }
                if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
                    //如果设置了借用时,校验对象,则调用factory.validateObject校验对象
                    boolean validate = false;
                    Throwable validationThrowable = null;
                    try {
                        validate = factory.validateObject(p);
                    } catch (Throwable t) {
                        PoolUtils.checkRethrow(t);
                        validationThrowable = t;
                    }
                    if (!validate) {
                        try {
                            //校验失败,销毁对象
                            destroy(p);
                            destroyedByBorrowValidationCount.incrementAndGet();
                        } catch (Exception e) {
                            // Ignore - validation failure is more important
                        }
                        p = null;
                        if (create) {
                            NoSuchElementException nsee = new NoSuchElementException(
                                    "Unable to validate object");
                            nsee.initCause(validationThrowable);
                            throw nsee;
                        }
                    }
                }
            }
        }
        //统计对象池的使用情况
        updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
        //返回获取的对象
        return p.getObject();
    }

returnObject 归还对象

private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
    new ConcurrentHashMap<IdentityWrapper<T>, PooledObject<T>>();//用于统计对象的map
 public void returnObject(T obj) {
        //对象池中是否有这个要归还的对象
        PooledObject<T> p = allObjects.get(new IdentityWrapper<T>(obj));

        if (p == null) {
            if (!isAbandonedConfig()) {
                throw new IllegalStateException(
                        "Returned object not currently part of this pool");
            } else {
                return; // Object was abandoned and removed
            }
        }

        synchronized(p) {
            //判断对象的状态,如果为ALLOCATED表明已经被归还了,抛出异常
            final PooledObjectState state = p.getState();
            if (state != PooledObjectState.ALLOCATED) {
                throw new IllegalStateException(
                        "Object has already been returned to this pool or is invalid");
            } else {
                //对象状态更改为RETURNING
                p.markReturning(); // Keep from being marked abandoned
            }
        }

        long activeTime = p.getActiveTimeMillis();
        //归还时是否校验对象
        if (getTestOnReturn()) {
            if (!factory.validateObject(p)) {
                try {
                    destroy(p);
                } catch (Exception e) {
                    swallowException(e);
                }
                try {
                    ensureIdle(1, false);
                } catch (Exception e) {
                    swallowException(e);
                }
                updateStatsReturn(activeTime);
                return;
            }
        }

        //钝化对象
        try {
            factory.passivateObject(p);
        } catch (Exception e1) {
            swallowException(e1);
            try {
                destroy(p);
            } catch (Exception e) {
                swallowException(e);
            }
            try {
                ensureIdle(1, false);
            } catch (Exception e) {
                swallowException(e);
            }
            //统计returnedCount和activeTimes
            updateStatsReturn(activeTime);
            return;
        }
        //将对象状态更改为:IDLE
        if (!p.deallocate()) {
            throw new IllegalStateException(
                    "Object has already been returned to this pool or is invalid");
        }

        int maxIdleSave = getMaxIdle();
        if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
            //如果超过对象池最大空闲数量,则将当前归还的p销毁
            try {
                destroy(p);
            } catch (Exception e) {
                swallowException(e);
            }
        } else {
            //归还,将对象重新如队列,具体的入队列方式,根据实际设置的队列存取,true放到队列头部,false放到队列尾部
            if (getLifo()) {
                idleObjects.addFirst(p);
            } else {
                idleObjects.addLast(p);
            }
            if (isClosed()) {
                // Pool closed while object was being added to idle objects.
                // Make sure the returned object is destroyed rather than left
                // in the idle object pool (which would effectively be a leak)
                clear();
            }
        }
        //更新对象池统计信息
        updateStatsReturn(activeTime);
    }

对象的状态

属性描述
IDLE空闲
ALLOCATED使用
EVICTION在队列中,有效
EVICTION_RETURN_TO_HEAD不在队列中,当前正在被检测,需要时会被归还到队头
VALIDATION在队列中,有效
VALIDATION_PREALLOCATED不在队列中,对象被借用,正在验证
VALIDATION_RETURN_TO_HEAD不在队列中,对象在验证,校验完成会被放到队列头部
INVALID非法
ABANDONED抛弃
RETURNING归还

结语

第一版我们使用的是commons-pool-1.6版本,后面升级为2.4.2版本,两个版本在对象池的管理上,2.4.2版本更胜一筹,队列中放置的不再单单是对象,而是对象的封装PooledObject,里面封装了对象的一些状态,便于后续进一步的对象管理。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值