1. 程式人生 > >commons-pool2原始碼走讀(三) 抽象物件池BaseGenericObjectPool

commons-pool2原始碼走讀(三) 抽象物件池BaseGenericObjectPool

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值