commons-pool2源码走读(三) 抽象对象池BaseGenericObjectPool

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq447995687/article/details/80444627

commons-pool2源码走读(三) 对象池BaseGenericObjectPool<T>

BaseGenericObjectPool<T>为GenericObjectPool和GenericKeyedObjectPool提供通用功能的基类。这个类存在的主要原因是减少两个池实现之间的代码复制。

1. 属性加载

BaseGenericObjectPool<T> 定义了所有能够自定义的属性,在类进行初始化的时候设置属性的默认值为BaseObjectPoolConfig和GenericKeyedObjectPoolConfig的默认值。然后子类通过继承其set方法重新覆盖(或延用)默认值。
其属性定义如下,可以看到所有的属性都是volatile的私有变量(fairness除外,在初始化指定后不再变化)。因为属性的变化不依赖之前的值,相较于使用锁而言使用volatile更加快捷高效。


    // 最大连接数,默认-1,当值为负数,使用Integer.MAX_VALUE代替
    private volatile int maxTotal =
            GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
    //当活跃对象总数达到上限,继续调用borrowObject是是否阻塞,默认true阻塞
    private volatile boolean blockWhenExhausted =
            BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
    //等待连接的超时时间,当blockWhenExhausted =ture,超过该值还未获得对象抛出异常。
    private volatile long maxWaitMillis =
            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
    //是否使用先进先出策略,默认true
    private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
    //是否使用平锁,默认false
    private final boolean fairness;
    //在创建对象的时候测试该对象,默认false
    private volatile boolean testOnCreate =
            BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
    //在借用对象的时候测试该对象,默认false
    private volatile boolean testOnBorrow =
            BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
    //在归还对象的时候测试该对象,默认false
    private volatile boolean testOnReturn =
            BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
    //在对象空闲的时候测试该对象,默认false
    private volatile boolean testWhileIdle =
            BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
    //回收线程的执行周期,即多长时候执行一次空闲对象检测。单位是毫秒数。
    //如果小于等于0,则不执行检测线程。默认值是-1;
    private volatile long timeBetweenEvictionRunsMillis =
            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
    //回收线程每次回收时检测的空闲对象个数,即可能不是每个空闲对象都会进行检测是否能够被回收
    //当值>=0时,取该数与空闲对象总数的较小值。<0时:空闲总数/该值绝对值,并向上取整。默认3
    private volatile int numTestsPerEvictionRun =
            BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
    //空闲对象被回收的最小空闲时间,默认30分钟,空闲时间超过30分钟的对象将被回收线程强制回收,
    //不会保留最小的空闲对象数量
    private volatile long minEvictableIdleTimeMillis =
            BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    //也是空闲对象被回收的时间,与minEvictableIdleTimeMillis不同的是当空闲数量<最小空闲数量要求时,
    //如果回收线程检测到该对象,既使该对象的超时时间已溢出,但是也不会被回收。
    //这个之后对EvictionPolicy做详细说明。默认-1
    private volatile long softMinEvictableIdleTimeMillis =
            BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    //回收策略,根据minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis
    //以及minIdle参数判断对象是否能够被回收
    private volatile EvictionPolicy<T> evictionPolicy;
    //shutdown一个回收线程的超时时间,在创建回收线程的时候,如果发现已有一个回收线程,
    //会将当前回收线程shutdown,并重新开启一个回收线程。默认10s
    private volatile long evictorShutdownTimeoutMillis =
            BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;

其它属性,用于同步操作的锁和对象池的计数信息。

    // 对象锁,用于子类
    final Object closeLock = new Object();
    //标识池是否关闭,用于子类。volatile 线程安全
    volatile boolean closed = false;
    //初始化回收线程时使用的对象锁
    final Object evictionLock = new Object();
    //回收线程
    private Evictor evictor = null; // @GuardedBy("evictionLock")
    EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
    private final WeakReference<ClassLoader> factoryClassLoader;
    //jmxObjectName 
    private final ObjectName oname;
    //调用堆栈
    private final String creationStackTrace;
    //总借出次数
    private final AtomicLong borrowedCount = new AtomicLong(0);
    ////总归还次数
    private final AtomicLong returnedCount = new AtomicLong(0);
    //总创建次数
    final AtomicLong createdCount = new AtomicLong(0);
    //总创销毁次数
    final AtomicLong destroyedCount = new AtomicLong(0);
    //总被回收销毁次数
    final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
    //总借用时校验不通过而被销毁次数
    final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
    //一个存放对象存活时间的缓存类,下面的几个StatsStore 类似
    private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
    private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
    private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
    //借用对象时的最大等待时间
    private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
    private volatile SwallowedExceptionListener swallowedExceptionListener = null;

2. 初始化

构造函数初始化jmx、创建堆栈、factoryClassLoader和fairness

    public BaseGenericObjectPool(final BaseObjectPoolConfig config,
            final String jmxNameBase, final String jmxNamePrefix) {
        //设置并注册jmx
        if (config.getJmxEnabled()) {
            this.oname = jmxRegister(config, jmxNameBase, jmxNamePrefix);
        } else {
            this.oname = null;
        }

        // 创建堆栈
        this.creationStackTrace = getStackTrace(new Exception());

        // 初始化factoryClassLoader,将会用于回收线程的初始化
        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            factoryClassLoader = null;
        } else {
            factoryClassLoader = new WeakReference<>(cl);
        }
        //设置是否使用公平锁
        fairness = config.getFairness();
    }

3. 回收线程

为了防止对象池泄漏,强制销毁一些非正常的对象。BaseGenericObjectPool使用TimerTask实现了一个定时回收任务

class Evictor extends TimerTask {
        /**
         * Run pool maintenance.  Evict objects qualifying for eviction and then
         * ensure that the minimum number of idle instances are available.
         * Since the Timer that invokes Evictors is shared for all Pools but
         * pools may exist in different class loaders, the Evictor ensures that
         * any actions taken are under the class loader of the factory
         * associated with the pool.
         */
        @Override
        public void run() {
            final ClassLoader savedClassLoader =
                    Thread.currentThread().getContextClassLoader();
            try {
            /**
             * 注意factoryClassLoader是WeakReference类型
             * 当gc时jvm会回收该对象(直接抛弃),相比于close,以此来确保factoryClassLoader一定能被释放gc掉,
             * 因此通过检测factoryClassLoader是否为null,来注销该timer,以保证对象池也能被gc,
             * 避免因无法close对象池(timer生成的线程为非守护线程,导致无法被gc回收?待确认)而带来的内存泄漏。
             */
                if (factoryClassLoader != null) {
                    // Set the class loader for the factory
                    final ClassLoader cl = factoryClassLoader.get();
                    if (cl == null) {
                        cancel();
                        return;
                    }
                    Thread.currentThread().setContextClassLoader(cl);
                }

                // Evict from the pool
                try {
                //回收对象,抽象方法
                    evict();
                } catch(final Exception e) {
                    swallowException(e);
                } catch(final OutOfMemoryError oome) {
                    // Log problem but give evictor thread a chance to continue
                    // in case error is recoverable
                    oome.printStackTrace(System.err);
                }

                try {
                //重新创建空闲对象,确保池中最小空闲连接数量
                    ensureMinIdle();
                } catch (final Exception e) {
                    swallowException(e);
                }
            } finally {
                // Restore the previous CCL
                Thread.currentThread().setContextClassLoader(savedClassLoader);
            }
        }
    }

空闲对象的一个iterator,用于回收线程遍历空闲对象,迭代器模式

class EvictionIterator implements Iterator<PooledObject<T>> {

        //空闲对象列表
        private final Deque<PooledObject<T>> idleObjects;
        //Iterator
        private final Iterator<PooledObject<T>> idleObjectIterator;
        EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
            this.idleObjects = idleObjects;

            if (getLifo()) {
                idleObjectIterator = idleObjects.descendingIterator();
            } else {
                idleObjectIterator = idleObjects.iterator();
            }
        }

        /**
         * Returns the idle object deque referenced by this iterator.
         * @return the idle object deque
         */
        public Deque<PooledObject<T>> getIdleObjects() {
            return idleObjects;
        }

        /** {@inheritDoc} */
        @Override
        public boolean hasNext() {
            return idleObjectIterator.hasNext();
        }

        /** {@inheritDoc} */
        @Override
        public PooledObject<T> next() {
            return idleObjectIterator.next();
        }

        /** {@inheritDoc} */
        @Override
        public void remove() {
            idleObjectIterator.remove();
        }

    }

4. IdentityWrapper对象包装器

由池管理的对象的包装器。GenericObjectPool和GenericKeyedObjectPool使用该包装器作为键值来映射PooledObject。这个包装类重写了hashCode,equals确保对象可以作为散列键。

static class IdentityWrapper<T> {
        /** Wrapped object */
        private final T instance;

        /**
         * Create a wrapper for an instance.
         *
         * @param instance object to wrap
         */
        public IdentityWrapper(final T instance) {
            this.instance = instance;
        }

        @Override
        public int hashCode() {
            //使用内存地址作为hashcode值,确保唯一性
            return System.identityHashCode(instance);
        }

        @Override
        @SuppressWarnings("rawtypes")
        public boolean equals(final Object other) {
            return  other instanceof IdentityWrapper &&
                    ((IdentityWrapper) other).instance == instance;
        }

        /**
         * @return the wrapped object
         */
        public T getObject() {
            return instance;
        }

        @Override
        public String toString() {
            final StringBuilder builder = new StringBuilder();
            builder.append("IdentityWrapper [instance=");
            builder.append(instance);
            builder.append("]");
            return builder.toString();
        }
    }

finally

由上可以看见BaseGenericObjectPool总共做了一下几件事,并未子类提供了公共的功能模块:

  1. 默认属性配置
  2. 对象池的计数信息
  3. 一个回收(驱逐)线程
  4. 实现了空闲对象的迭代器
  5. 注册jmx
  6. 定义IdentityWrapper作为保存所有对象的map容器的key值

猜你喜欢

转载自blog.csdn.net/qq447995687/article/details/80444627
今日推荐