本文以apache common-pools为例

主要组成类


PooledObject(可被池化的对象)

默认实现DefaultPooledObject,里面封装了一个真正的用户需要池化的对象object。

springboot对象池使用实战_堆栈

其中DefaultPooledObject里面有两个方法:

Exception borrowedBy :用于记录上次调用borrow时的堆栈,用于跟踪代码调用情况

@Override
    public synchronized boolean allocate() {
        if (state == PooledObjectState.IDLE) {
            state = PooledObjectState.ALLOCATED;
            lastBorrowTime = System.currentTimeMillis();
            lastUseTime = lastBorrowTime;
            borrowedCount++;
            if (logAbandoned) {
                        borrowedBy = new  AbandonedObjectCreatedException();
            } 
            return true;
        } else if (state == PooledObjectState.EVICTION) {
            // TODO Allocate anyway and ignore eviction test
            state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
            return false;
        }
        // TODO if validating and testOnBorrow == true then pre-allocate for
        // performance
        return false;
    }

Exception usedBy: 同上,记录use时的堆栈

@Override
    public void use() {
        lastUseTime = System.currentTimeMillis();
        usedBy = new Exception("The last code to use this object was:");
    }
PooledObjectState

对象的状态,也即生命周期

springboot对象池使用实战_springboot对象池使用实战_02

  • allocated :此对象被客户端使用中
  • idle :在池中,处于空闲状态
  • eviction:在实例化GenericObjectPool对象时,内部会启动一个EvictionTimer线程线程,定期(timeBetweenEvictionRunsMillis)执行evict方法,以EvictionPolicy策略destory 状态处于idle过长的对象或idle数太多的时候。
  • abandoned:当池中的对象被客户端拿出后,若长时间(removeAbandonedTimeout)未返回池中,或没有调用use方法,即被标记为抛弃的,当执行removeAbandoned方法时从池中destory,并若logAbandoned为true的话,则打印调用堆栈
PooledObjectFactory(对象创建工厂)

springboot对象池使用实战_ide_03

一般需要程序员继承BasePooledObjectFactory,创建需要池化的对象:

private static class ShardedJedisFactory implements PooledObjectFactory<ShardedJedis> {
    private List<JedisShardInfo> shards;
    private Hashing algo;
    private Pattern keyTagPattern;

    public ShardedJedisFactory(List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
      this.shards = shards;
      this.algo = algo;
      this.keyTagPattern = keyTagPattern;
    }

    @Override
    public PooledObject<ShardedJedis> makeObject() throws Exception {
      ShardedJedis jedis = new ShardedJedis(shards, algo, keyTagPattern);
      return new DefaultPooledObject<ShardedJedis>(jedis);
    }

    @Override
    public void destroyObject(PooledObject<ShardedJedis> pooledShardedJedis) throws Exception {
      final ShardedJedis shardedJedis = pooledShardedJedis.getObject();
      for (Jedis jedis : shardedJedis.getAllShards()) {
        if (jedis.isConnected()) {
          try {
            try {
              jedis.quit();
            } catch (Exception e) {

            }
            jedis.disconnect();
          } catch (Exception e) {

          }
        }
      }
    }

    @Override
    public boolean validateObject(PooledObject<ShardedJedis> pooledShardedJedis) {
      try {
        ShardedJedis jedis = pooledShardedJedis.getObject();
        for (Jedis shard : jedis.getAllShards()) {
          if (!shard.ping().equals("PONG")) {
            return false;
          }
        }
        return true;
      } catch (Exception ex) {
        return false;
      }
    }

    @Override
    public void activateObject(PooledObject<ShardedJedis> p) throws Exception {

    }

    @Override
    public void passivateObject(PooledObject<ShardedJedis> p) throws Exception {

    }
  }
GenericObjectPoolConfig(对象池配置)

springboot对象池使用实战_堆栈_04

  • lifo:后进先出,或者先进先出
  • maxWaitMillis:从idle队列里面取对象时,若阻塞的话,则最大等待时长
  • minEvictableIdleTimeMillis:处于idle状态超过此值时,会被destory
  • softMinEvictableIdleTimeMillis:处于idle状态超过此值,且处于idle状态个数大于minIdle时会被destory ,正常情况下softMinEvictableIdleTimeMillis < minEvictableIdleTimeMillis
  • numTestsPerEvictionRun: evict线程每次遍历时evict的个数
  • testOnCreate:当create对象时,是否测试池化的对象是否存活
  • testOnBorrow: 同上,从池中borrow出来时测试
  • testOnReturn:同上,归还池中时测试
  • testWhileIdle:同上,idle状态时测试
  • timeBetweenEvictionRunsMillis:evict线程每次间隔时间
  • blockWhenExhausted:从池中取对象时,若池子用尽的话,是否阻塞等待一会maxWaitMillis
  • jmxEnabled:jmx是否开启监控
AbandonedConfig(防止对象泄露)

springboot对象池使用实战_池化_05

  • abandoned:被抛弃的,即被池抛弃的设置(客户端从池里面取出去后,若长时间不归还池中,则抛弃并destory)并通过配置可以设置是否logAbandoned,若true的话,则把抛弃对象时,打印相关的日志(调用日志)

主要流程


evict线程流程

springboot对象池使用实战_堆栈_06