`

[实现剖析] Apache Commons Pool之空闲对象的驱逐检测机制

阅读更多

本文主要剖析 Apache Commons Pool 的“空闲对象的驱逐检测机制”的实现原理。

 

以下面3个步骤来循序渐进地深入剖析其实现原理

  1. 启动“空闲对象驱逐者线程”(startEvictor(...))的2个入口
  2. 在启动时,创建一个新的"驱逐者线程"(Evictor),并使用"驱逐者定时器"(EvictionTimer)进行调度
  3. 进入真正地"空闲池对象"的驱逐检测操作(evict())

下图是“空闲对象的驱逐检测机制”处理流程的时序图(阅读代码时结合着看可以加深理解):

GenericObjectPool.evict() 处理流程的时序图:

GenericObjectPool.ensureMinIdle()处理流程的时序图:

 

一、启动“空闲对象的驱逐者线程”(startEvictor(...))共有2个入口

1. GenericObjectPool 构造方法

GenericObjectPool(...):初始化"池对象工厂",设置"对象池配置",并启动"驱逐者线程"。

    /**
     * 使用特定的配置来创建一个新的"通用对象池"实例。
     *
     * @param factory   The object factory to be used to create object instances
     *                  used by this pool (用于创建池对象实例的对象工厂)
     * @param config    The configuration to use for this pool instance. (用于该对象池实例的配置信息)
     *                  The configuration is used by value. Subsequent changes to
     *                  the configuration object will not be reflected in the
     *                  pool. (随后对配置对象的更改将不会反映到池中)
     */
    public GenericObjectPool(PooledObjectFactory<T> factory,
            GenericObjectPoolConfig config) {

        super(config, ONAME_BASE, config.getJmxNamePrefix());

        if (factory == null) {
            jmxUnregister(); // tidy up
            throw new IllegalArgumentException("factory may not be null");
        }
        this.factory = factory;

        this.setConfig(config);
        // 启动"驱逐者线程"
        startEvictor(this.getTimeBetweenEvictionRunsMillis());
    }

 

2. BaseGenericObjectPool.setTimeBetweenEvictionRunsMillis(...) - 设置"驱逐者线程"的运行间隔时间

可以动态地更新"驱逐者线程"的运行调度间隔时间。

    /**
     * 设置"空闲对象的驱逐者线程"的运行调度间隔时间。(同时,会立即启动"驱逐者线程")
     * <p>
     * 如果该值是非正数,则没有"空闲对象的驱逐者线程"将运行。
     * <p>
     * 默认是 {@code -1},即没有"空闲对象的驱逐者线程"在后台运行着。
     * <p>
     * 上一层入口:{@link GenericObjectPool#setConfig(GenericObjectPoolConfig)}<br>
     * 顶层入口:{@link GenericObjectPool#GenericObjectPool(PooledObjectFactory, GenericObjectPoolConfig)},
     * 在最后还会调用{@link #startEvictor(long)}来再次启动"空闲对象的驱逐者线程"。<br>
     * 这样在初始化时,这里创建的"驱逐者线程"就多余了,会立刻被销毁掉。<br>
     * 但这里为什么要这样实现呢?<br>
     * 我的理解是:为了能动态地更新"驱逐者线程"的调度间隔时间。
     *
     * @param timeBetweenEvictionRunsMillis
     *            number of milliseconds to sleep between evictor runs ("驱逐者线程"运行的间隔毫秒数)
     *
     * @see #getTimeBetweenEvictionRunsMillis
     */
    public final void setTimeBetweenEvictionRunsMillis(
            long timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        // 启动"驱逐者线程"
        this.startEvictor(timeBetweenEvictionRunsMillis);
    }

 

二、startEvictor(long delay) - 启动“空闲对象的驱逐者线程”

如果有一个"驱逐者线程"(Evictor)运行着,则会先停止它;

然后创建一个新的"驱逐者线程",并使用"驱逐者定时器"(EvictionTimer)进行调度。

    // 空闲对象的驱逐回收策略
    /** 用于初始化"驱逐者线程"的同步对象 */
    final Object evictionLock = new Object();
    /** 空闲对象驱逐者线程 */
    private Evictor evictor = null; // @GuardedBy("evictionLock")
    /** 驱逐检测对象迭代器 */
    Iterator<PooledObject<T>> evictionIterator = null; // @GuardedBy("evictionLock")

    /**
     * 启动"空闲对象的驱逐者线程"。
     * <p>
     * 如果有一个"驱逐者线程"({@link Evictor})运行着,则会先停止它;
     * 然后创建一个新的"驱逐者线程",并使用"驱逐者定时器"({@link EvictionTimer})进行调度。
     *
     * <p>This method needs to be final, since it is called from a constructor. (因为它被一个构造器调用)
     * See POOL-195.</p>
     *
     * @param delay time in milliseconds before start and between eviction runs (驱逐者线程运行的开始和间隔时间 毫秒数)
     */
    final void startEvictor(long delay) {
        synchronized (evictionLock) { // 同步锁
            if (null != evictor) {
            	// 先释放申请的资源
                EvictionTimer.cancel(evictor);
                evictor = null;
                evictionIterator = null;
            }
            if (delay > 0) {
                evictor = new Evictor();
                EvictionTimer.schedule(evictor, delay, delay);
            }
        }
    }

 

2.1 Evictor - "驱逐者线程"实现

Evictor,"空闲对象的驱逐者"定时任务,继承自 TimerTask。TimerTask 是一个可由定时器(Timer)调度执行一次或重复执行的任务。

核心实现逻辑:

1. evict():执行numTests个空闲池对象的驱逐测试,驱逐那些符合驱逐条件的被检测对象;
2. ensureMinIdle():试图确保配置的对象池中可用"空闲池对象"实例的最小数量。

    /**
     * Class loader for evictor thread to use since in a J2EE or similar
     * environment the context class loader for the evictor thread may have
     * visibility of the correct factory. See POOL-161.
     * 驱逐者线程的类加载器
     */
    private final ClassLoader factoryClassLoader;

    // Inner classes

    /**
     * "空闲对象的驱逐者"定时任务,继承自{@link TimerTask}。
     *
     * @see GenericObjectPool#GenericObjectPool(PooledObjectFactory, GenericObjectPoolConfig)
     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)
     */
    class Evictor extends TimerTask {

        /**
         * 运行对象池维护线程。
         * 驱逐对象具有驱逐者的资格,同时保证空闲实例可用的最小数量。
         * 因为调用"驱逐者线程"的定时器是被所有对象池共享的,
         * 但对象池可能存在不同的类加载器中,所以驱逐者必须确保采取的任何行为
         * 都得在与对象池相关的工厂的类加载器下。
         */
        @Override
        public void run() {
            ClassLoader savedClassLoader =
                    Thread.currentThread().getContextClassLoader();
            try {
                // Set the class loader for the factory (设置"工厂的类加载器")
                Thread.currentThread().setContextClassLoader(
                        factoryClassLoader);

                // Evict from the pool (从"对象池"中驱逐)
                try {
                    // 1. 执行numTests个空闲池对象的驱逐测试,驱逐那些符合驱逐条件的被检测对象
                    evict(); // 抽象方法
                } catch(Exception e) {
                    swallowException(e);
                } catch(OutOfMemoryError oome) {
                    // Log problem but give evictor thread a chance to continue
                    // in case error is recoverable
                    oome.printStackTrace(System.err);
                }
                // Re-create idle instances. (重新创建"空闲池对象"实例)
                try {
                    // 2. 试图确保配置的对象池中可用"空闲池对象"实例的最小数量
                    ensureMinIdle(); // 抽象方法
                } catch (Exception e) {
                    swallowException(e);
                }
            } finally {
                // Restore the previous CCL
                Thread.currentThread().setContextClassLoader(savedClassLoader);
            }
        }
    }

 

2.2 EvictionTimer - "驱逐者定时器"实现

EvictionTimer,提供一个所有"对象池"共享的"空闲对象驱逐定时器"。此类包装标准的定时器(Timer),并追踪有多少个"对象池"使用它。

核心实现逻辑:

schedule(TimerTask task, long delay, long period):添加指定的驱逐任务到这个定时器

/**
 * 提供一个所有"对象池"共享的"空闲对象的驱逐定时器"。
 * 
 * 此类包装标准的定时器({@link Timer}),并追踪有多少个对象池使用它。
 * 
 * 如果没有对象池使用这个定时器,它会被取消。这样可以防止线程一直运行着
 * (这会导致内存泄漏),防止应用程序关闭或重新加载。
 * <p>
 * 此类是包范围的,以防止其被纳入到池框架的公共API中。
 * <p>
 * <font color="red">此类是线程安全的!</font>
 *
 * @since 2.0
 */
class EvictionTimer {

    /** Timer instance (定时器实例) */
    private static Timer _timer; //@GuardedBy("this")

    /** Static usage count tracker (使用计数追踪器) */
    private static int _usageCount; //@GuardedBy("this")

    /** Prevent instantiation (防止实例化) */
    private EvictionTimer() {
        // Hide the default constructor
    }

    /**
     * 添加指定的驱逐任务到这个定时器。
     * 任务,通过调用该方法添加的,必须调用{@link #cancel(TimerTask)}来取消这个任务,
     * 以防止内存或消除泄漏。
     * 
     * @param task      Task to be scheduled (定时调度的任务)
     * @param delay     Delay in milliseconds before task is executed (任务执行前的等待时间)
     * @param period    Time in milliseconds between executions (执行间隔时间)
     */
    static synchronized void schedule(TimerTask task, long delay, long period) {
        if (null == _timer) {
            // Force the new Timer thread to be created with a context class
            // loader set to the class loader that loaded this library
            ClassLoader ccl = AccessController.doPrivileged(
                    new PrivilegedGetTccl());
            try {
                AccessController.doPrivileged(new PrivilegedSetTccl(
                        EvictionTimer.class.getClassLoader()));
                _timer = new Timer("commons-pool-EvictionTimer", true);
            } finally {
                AccessController.doPrivileged(new PrivilegedSetTccl(ccl));
            }
        }
        // 增加"使用计数器",并调度"任务"
        _usageCount++;
        _timer.schedule(task, delay, period);
    }

    /**
     * 从定时器中删除指定的驱逐者任务。
     * <p>
     * Remove the specified eviction task from the timer.
     * 
     * @param task      Task to be scheduled (定时调度任务)
     */
    static synchronized void cancel(TimerTask task) {
        task.cancel(); // 1. 将任务的状态标记为"取消(CANCELLED)"状态
        _usageCount--;
        if (_usageCount == 0) { // 2. 如果没有对象池使用这个定时器,定时器就会被取消
            _timer.cancel();
            _timer = null;
        }
    }

    /**
     * {@link PrivilegedAction} used to get the ContextClassLoader (获取"上下文类加载器")
     */
    private static class PrivilegedGetTccl implements PrivilegedAction<ClassLoader> {

        @Override
        public ClassLoader run() {
            return Thread.currentThread().getContextClassLoader();
        }
    }

    /**
     * {@link PrivilegedAction} used to set the ContextClassLoader (设置"上下文类加载器")
     */
    private static class PrivilegedSetTccl implements PrivilegedAction<Void> {

        /** ClassLoader */
        private final ClassLoader cl;

        /**
         * Create a new PrivilegedSetTccl using the given classloader
         * @param cl ClassLoader to use
         */
        PrivilegedSetTccl(ClassLoader cl) {
            this.cl = cl;
        }

        @Override
        public Void run() {
            Thread.currentThread().setContextClassLoader(cl);
            return null;
        }
    }

}

 

三、"驱逐者线程"和"驱逐者定时器"都准备就绪,现在真正地开始"空闲池对象"的驱逐检测操作(evict()

BaseGenericObjectPool.evict():驱逐检测操作的抽象声明

    /**
     * 执行{@link numTests}个空闲池对象的驱逐测试,驱逐那些符合驱逐条件的被检测对象。
     * <p>
     * 如果{@code testWhileIdle}为{@code true},则被检测的对象在访问期间是有效的(无效则会被删除);
     * 否则,仅有那些池对象的空闲时间超过{@code minEvicableIdleTimeMillis}会被删除。
     *
     * @throws Exception when there is a problem evicting idle objects. (当这是一个有问题的驱逐空闲池对象时,才会抛出Exception异常。)
     */
    public abstract void evict() throws Exception;

GenericObjectPool.evict():"通用对象池"的驱逐检测操作实现

核心实现逻辑:

1. 确保"对象池"还打开着

2. 获取"驱逐回收策略"

3. 获取"驱逐配置"

4. 对所有待检测的"空闲对象"进行驱逐检测

4.1 初始化"驱逐检测对象(空闲池对象)的迭代器"

4.2 将"池对象"标记为"开始驱逐状态"

4.3 进行真正的"驱逐检测"操作(EvictionPolicy.evict(...)

4.3.1 如果"池对象"是可驱逐的,则销毁它

4.3.2 否则,是否允许空闲时进行有效性测试

4.3.2.1 先激活"池对象"

4.3.2.2 使用PooledObjectFactory.validateObject(PooledObject)进行"池对象"的有效性校验

4.3.2.2.1 如果"池对象"不是有效的,则销毁它

4.3.2.2.2 否则,还原"池对象"状态

4.3.2.3 通知"空闲对象队列",驱逐测试已经结束

5. 是否要移除"被废弃的池对象"

    /** 池的空闲池对象列表 */
    private final LinkedBlockingDeque<PooledObject<T>> idleObjects =
        new LinkedBlockingDeque<PooledObject<T>>();
    /** 池对象工厂 */
    private final PooledObjectFactory<T> factory;

    // 空闲对象的驱逐回收策略
    /** 用于初始化"驱逐者线程"的同步对象 */
    final Object evictionLock = new Object();
    /** 空闲对象驱逐者线程 */
    private Evictor evictor = null; // @GuardedBy("evictionLock")
    /** 驱逐检测对象("空闲池对象")的迭代器 */
    Iterator<PooledObject<T>> evictionIterator = null; // @GuardedBy("evictionLock")

    /** 被废弃的池对象追踪的配置属性 */
    private volatile AbandonedConfig abandonedConfig = null;

    /**
     * {@inheritDoc}
     * <p>
     * 按顺序对被审查的对象进行连续驱逐检测,对象是以"从最老到最年轻"的顺序循环。
     */
    @Override
    public void evict() throws Exception {
    	// 1. 确保"对象池"还打开着
        this.assertOpen();

        if (idleObjects.size() > 0) {
            PooledObject<T> underTest = null; // 测试中的池对象
            // 2. 获取"驱逐回收策略"
            EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy();

            synchronized (evictionLock) { // 驱逐锁定
            	// 3. 获取"驱逐配置"
                EvictionConfig evictionConfig = new EvictionConfig(
                		this.getMinEvictableIdleTimeMillis(),
                		this.getSoftMinEvictableIdleTimeMillis(),
                		this.getMinIdle()
                		);

                // 4. 对所有待检测的"空闲对象"进行驱逐检测
                for (int i = 0, m = this.getNumTests(); i < m; i++) {
                	// 4.1 初始化"驱逐检测对象(空闲池对象)的迭代器"
                    if (evictionIterator == null || !evictionIterator.hasNext()) { // 已对所有空闲对象完成一次遍历
                    	// 根据"对象池使用行为"赋值驱逐迭代器
                        if (this.getLifo()) {
                            evictionIterator = idleObjects.descendingIterator();
                        } else {
                            evictionIterator = idleObjects.iterator();
                        }
                    }
                    if (!evictionIterator.hasNext()) {
                        // Pool exhausted, nothing to do here (对象池被耗尽,无可用池对象)
                        return;
                    }

                    try {
                        underTest = evictionIterator.next();
                    } catch (NoSuchElementException nsee) {
                        // Object was borrowed in another thread (池对象被其它请求线程借用了)
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        evictionIterator = null;
                        continue;
                    }

                    // 4.2 将"池对象"标记为"开始驱逐状态"
                    if (!underTest.startEvictionTest()) {
                        // Object was borrowed in another thread
                        // Don't count this as an eviction test so reduce i;
                        i--;
                        continue;
                    }
                    
                    boolean testWhileIdle = this.getTestWhileIdle(); // 是否要在对象空闲时测试有效性

                    // 4.3 进行真正的"驱逐检测"操作(EvictionPolicy.evict(...))
                    if (evictionPolicy.evict(evictionConfig, underTest,
                            idleObjects.size())) {
                    	// 4.3.1 如果"池对象"是可驱逐的,则销毁它
                    	this.destroy(underTest);
                        destroyedByEvictorCount.incrementAndGet();
                    } else {
                    	// 4.3.2 否则,是否允许空闲时进行有效性测试
                        if (testWhileIdle) { // 允许空闲时进行有效性测试
                        	// 4.3.2.1 先激活"池对象"
                            boolean active = false;
                            try {
                                factory.activateObject(underTest);
                                active = true;
                            } catch (Exception e) {
                            	this.destroy(underTest);
                                destroyedByEvictorCount.incrementAndGet();
                            }
                            // 4.3.2.2 使用PooledObjectFactory.validateObject(PooledObject)进行"池对象"的有效性校验
                            if (active) {
                                if (!factory.validateObject(underTest)) {
                                	// 4.3.2.2.1 如果"池对象"不是有效的,则销毁它
                                	this.destroy(underTest);
                                    destroyedByEvictorCount.incrementAndGet();
                                } else {
                                    try {
                                    	// 4.3.2.2.2 否则,还原"池对象"状态
                                        factory.passivateObject(underTest);
                                    } catch (Exception e) {
                                    	this.destroy(underTest);
                                        destroyedByEvictorCount.incrementAndGet();
                                    }
                                }
                            }
                        }
                        // 4.3.2.3 通知"空闲对象队列",驱逐测试已经结束
                        if (!underTest.endEvictionTest(idleObjects)) {
                            // TODO - May need to add code here once additional
                            // states are used
                        }
                    }
                }
            }
        }
        // 5. 是否要移除"被废弃的池对象"
        AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
        	this.removeAbandoned(ac);
        }
    }

BaseGenericObjectPool.ensureMinIdle():"确保对象池中可用"空闲池对象"实例的最小数量"的抽象声明

 

    /**
     * 试图确保配置的对象池中可用"空闲池对象"实例的最小数量。
     * 
     * @throws Exception if an error occurs creating idle instances
     */
    abstract void ensureMinIdle() throws Exception;
 

 

GenericObjectPool.ensureMinIdle():"确保对象池中可用"空闲池对象"实例的最小数量"实现

    @Override
    void ensureMinIdle() throws Exception {
        this.ensureIdle(this.getMinIdle(), true);
    }

    /**
     * 返回对象池中维护的空闲对象的最小数量目标。
     * <p>
     * 此设置仅会在{@link #getTimeBetweenEvictionRunsMillis()}的返回值大于0时,
     * 且该值是正整数时才会生效。
     * <p>
     * 默认是 {@code 0},即对象池不维护空闲的池对象。
     * 
     * @return The minimum number of objects. (空闲对象的最小数量)
     *
     * @see #setMinIdle(int)
     * @see #setMaxIdle(int)
     * @see #setTimeBetweenEvictionRunsMillis(long)
     */
    @Override
    public int getMinIdle() {
        int maxIdleSave = this.getMaxIdle();
        if (this.minIdle > maxIdleSave) {
            return maxIdleSave;
        } else {
            return minIdle;
        }
    }

    /**
     * 试图确保对象池中存在的{@code idleCount}个空闲实例。
     * <p>
     * 创建并添加空闲实例,直到空闲实例数量({@link #getNumIdle()})达到{@code idleCount}个,
     * 或者池对象的总数(空闲、检出、被创建)达到{@link #getMaxTotal()}。
     * 如果{@code always}是false,则不会创建实例,除非线程在等待对象池中的实例检出。
     * 
     * @param idleCount the number of idle instances desired (期望的空闲实例数量)
     * @param always true means create instances even if the pool has no threads waiting
     * 			(true意味着即使对象池没有线程等待,也会创建实例)
     * @throws Exception if the factory's makeObject throws
     */
    private void ensureIdle(int idleCount, boolean always) throws Exception {
        if (idleCount < 1 || this.isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
            return;
        }

        while (idleObjects.size() < idleCount) {
            PooledObject<T> p = this.create();
            if (p == null) {
                // Can't create objects (不能创建对象), no reason to think another call to
                // create will work. Give up.
                break;
            }
            // "新的池对象"可以立刻被使用
            if (this.getLifo()) { // LIFO(后进先出)
                idleObjects.addFirst(p);
            } else { // FIFO(先进先出)
                idleObjects.addLast(p);
            }
        }
    }

    /**
     * 尝试着创建一个新的包装的池对象。
     *
     * @return The new wrapped pooled object
     *
     * @throws Exception if the object factory's {@code makeObject} fails
     */
    private PooledObject<T> create() throws Exception {
    	// 1. 对象池是否被耗尽判断
        int localMaxTotal = getMaxTotal();
        long newCreateCount = createCount.incrementAndGet();
        if (localMaxTotal > -1 && newCreateCount > localMaxTotal ||
                newCreateCount > Integer.MAX_VALUE) {
            createCount.decrementAndGet();
            return null; // 没有池对象可创建
        }

        final PooledObject<T> p;
        try {
            // 2. 使用PooledObjectFactory.makeObject()来制造一个新的池对象
            p = factory.makeObject();
        } catch (Exception e) {
            createCount.decrementAndGet();
            throw e;
        }

        AbandonedConfig ac = this.abandonedConfig;
        if (ac != null && ac.getLogAbandoned()) {
            p.setLogAbandoned(true);
        }

        createdCount.incrementAndGet();
        // 3. 将新创建的池对象追加到"池的所有对象映射表"中
        allObjects.put(p.getObject(), p);
        return p;
    }

 

3.1 "驱逐回收策略"实现

EvictionConfig:"驱逐回收策略"配置信息

/**
 * 此类用于将对象池的配置信息传递给"驱逐回收策略({@link EvictionPolicy})"实例。
 * <p>
 * <font color="red">此类是不可变的,且是线程安全的。</font>
 *
 * @since 2.0
 */
public class EvictionConfig {

    // final 字段修饰保证其不可变性
    /** 池对象的最大空闲驱逐时间(当池对象的空闲时间超过该值时,立马被强制驱逐掉) */
    private final long idleEvictTime;
    /** 池对象的最小空闲驱逐时间(当池对象的空闲时间超过该值时,被纳入驱逐对象列表里) */
    private final long idleSoftEvictTime;
    /** 对象池的最小空闲池对象数量 */
    private final int minIdle;


    /**
     * 创建一个新的"驱逐回收策略"配置实例。
     * <p>
     * <font color="red">实例是不可变的。</font>
     *
     * @param poolIdleEvictTime Expected to be provided by (池对象的最大空闲驱逐时间(ms))
     *        {@link BaseGenericObjectPool#getMinEvictableIdleTimeMillis()}
     * @param poolIdleSoftEvictTime Expected to be provided by (池对象的最小空闲驱逐时间(ms))
     *        {@link BaseGenericObjectPool#getSoftMinEvictableIdleTimeMillis()}
     * @param minIdle Expected to be provided by (对象池的最小空闲池对象数量)
     *        {@link GenericObjectPool#getMinIdle()} or
     *        {@link GenericKeyedObjectPool#getMinIdlePerKey()}
     */
    public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime,
            int minIdle) {
        if (poolIdleEvictTime > 0) {
            idleEvictTime = poolIdleEvictTime;
        } else {
            idleEvictTime = Long.MAX_VALUE;
        }
        if (poolIdleSoftEvictTime > 0) {
            idleSoftEvictTime = poolIdleSoftEvictTime;
        } else {
            idleSoftEvictTime  = Long.MAX_VALUE;
        }
        this.minIdle = minIdle;
    }

    /**
     * 获取"池对象的最大空闲驱逐时间(ms)"。
     * <p>
     * 当池对象的空闲时间超过该值时,立马被强制驱逐掉。
     * <p>
     * How the evictor behaves based on this value will be determined by the
     * configured {@link EvictionPolicy}.
     *
     * @return The {@code idleEvictTime} in milliseconds
     */
    public long getIdleEvictTime() {
        return idleEvictTime;
    }

    /**
     * 获取"池对象的最小空闲驱逐时间(ms)"。
     * <p>
     * 当池对象的空闲时间超过该值时,被纳入驱逐对象列表里。
     * <p>
     * How the evictor behaves based on this value will be determined by the
     * configured {@link EvictionPolicy}.
     *
     * @return The (@code idleSoftEvictTime} in milliseconds
     */
    public long getIdleSoftEvictTime() {
        return idleSoftEvictTime;
    }

    /**
     * 获取"对象池的最小空闲池对象数量"。
     * <p>
     * How the evictor behaves based on this value will be determined by the
     * configured {@link EvictionPolicy}.
     *
     * @return The {@code minIdle}
     */
    public int getMinIdle() {
        return minIdle;
    }

}

 

EvictionPolicy<T>:"驱逐回收策略"声明

/**
 * 为了提供对象池的一个自定义"驱逐回收策略",
 * 使用者必须提供该接口的一个实现(如{@link DefaultEvictionPolicy})。
 *
 * @param <T> the type of objects in the pool (对象池中对象的类型)
 *
 * @since 2.0
 */
public interface EvictionPolicy<T> {

    /**
     * 一个对象池中的空闲对象是否应该被驱逐,调用此方法来测试。(驱逐行为声明)
     *
     * @param config    The pool configuration settings related to eviction (与驱逐相关的对象池配置设置)
     * @param underTest The pooled object being tested for eviction (正在被驱逐测试的池对象)
     * @param idleCount The current number of idle objects in the pool including
     *                      the object under test (当前对象池中的空闲对象数,包括测试中的对象)
     * @return <code>true</code> if the object should be evicted, otherwise
     *             <code>false</code> (如果池对象应该被驱逐掉,就返回{@code true};否则,返回{@code false}。)
     */
    boolean evict(EvictionConfig config, PooledObject<T> underTest,
            int idleCount);

}

 

DefaultEvictionPolicy<T>:提供用在对象池的"驱逐回收策略"的默认实现,继承自EvictionPolicy<T>

/**
 * 提供用在对象池的"驱逐回收策略"的默认实现,继承自{@link EvictionPolicy}。
 * <p>
 * 如果满足以下条件,对象将被驱逐:
 * <ul>
 * <li>池对象的空闲时间超过{@link GenericObjectPool#getMinEvictableIdleTimeMillis()}
 * <li>对象池中的空闲对象数超过{@link GenericObjectPool#getMinIdle()},且池对象的空闲时间超过{@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()}
 * </ul>
 * <font color="red">此类是不可变的,且是线程安全的。</font>
 *
 * @param <T> the type of objects in the pool (对象池中对象的类型)
 *
 * @since 2.0
 */
public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {

    /**
     * 如果对象池中的空闲对象是否应该被驱逐,调用此方法来测试。(驱逐行为实现)
     */
    @Override
    public boolean evict(EvictionConfig config, PooledObject<T> underTest,
            int idleCount) {

    	if ((idleCount > config.getMinIdle() && 
    			underTest.getIdleTimeMillis() > config.getIdleSoftEvictTime()) 
    			|| underTest.getIdleTimeMillis() > config.getIdleEvictTime()) {
            return true;
        }
        return false;
    }

}

 

其他相关实现

 

    // --- internal attributes (内部属性) -------------------------------------------------

    /** 对象池中的所有池对象映射表 */
    private final ConcurrentMap<T, PooledObject<T>> allObjects =
        new ConcurrentHashMap<T, PooledObject<T>>();
    /** 池的空闲池对象列表 */
    private final LinkedBlockingDeque<PooledObject<T>> idleObjects =
        new LinkedBlockingDeque<PooledObject<T>>();

    /** 池对象工厂 */
    private final PooledObjectFactory<T> factory;


    /**
     * 计算空闲对象驱逐者一轮测试的对象数量。
     *
     * @return The number of objects to test for validity (要测试其有效性的对象数量)
     */
    private int getNumTests() {
        int numTestsPerEvictionRun = this.getNumTestsPerEvictionRun();
        if (numTestsPerEvictionRun >= 0) {
            return Math.min(numTestsPerEvictionRun, idleObjects.size());
        } else {
            return (int) (Math.ceil(idleObjects.size() /
                    Math.abs((double) numTestsPerEvictionRun)));
        }
    }

    /**
     * 销毁一个包装的"池对象"。
     *
     * @param toDestory The wrapped pooled object to destroy
     *
     * @throws Exception If the factory fails to destroy the pooled object
     *                   cleanly
     */
    private void destroy(PooledObject<T> toDestory) throws Exception {
    	// 1. 设置这个"池对象"的状态为"无效(INVALID)"
        toDestory.invalidate();
        // 2. 将这个"池对象"从"空闲对象列表"和"所有对象列表"中移除掉
        idleObjects.remove(toDestory);
        allObjects.remove(toDestory.getObject());
        try {
            // 3. 使用PooledObjectFactory.destroyObject(PooledObject<T> p)来销毁这个不再需要的池对象
            factory.destroyObject(toDestory);
        } finally {
            destroyedCount.incrementAndGet();
            createCount.decrementAndGet();
        }
    }

    /**
     * 恢复被废弃的对象,它已被检测出超过{@code AbandonedConfig#getRemoveAbandonedTimeout() 
     * removeAbandonedTimeout}未被使用。
     * <p>
     * <font color="red">注意:需要考虑性能损耗,因为它会对对象池中的所有池对象进行检测!</font>
     *
     * @param ac The configuration to use to identify abandoned objects
     */
    private void removeAbandoned(AbandonedConfig ac) {
        // 1. Generate a list of abandoned objects to remove (生成一个要被删除的被废弃的对象列表)
        final long now = System.currentTimeMillis();
        final long timeout =
                now - (ac.getRemoveAbandonedTimeout() * 1000L);
        List<PooledObject<T>> remove = new ArrayList<PooledObject<T>>();
        Iterator<PooledObject<T>> it = allObjects.values().iterator();
        while (it.hasNext()) {
            PooledObject<T> pooledObject = it.next();
            synchronized (pooledObject) {
            	// 从"所有池对象"中挑选出状态为"使用中"的池对象,且空闲时间已超过了"对象的移除超时时间"
                if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
                        pooledObject.getLastUsedTime() <= timeout) {
                	// 标记池对象为"被废弃"状态,并添加到删除列表中
                    pooledObject.markAbandoned();
                    remove.add(pooledObject);
                }
            }
        }

        // 2. Now remove the abandoned objects (移除所有被废弃的对象)
        Iterator<PooledObject<T>> itr = remove.iterator();
        while (itr.hasNext()) {
            PooledObject<T> pooledObject = itr.next();
            if (ac.getLogAbandoned()) {
                pooledObject.printStackTrace(ac.getLogWriter());
            }
            try {
                this.invalidateObject(pooledObject.getObject());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

 

 

综上所述,真正的"空闲对象的驱逐检测操作"在 GenericObjectPool.evict() 中实现,其被包装在"驱逐者定时器任务(Evictor)"中,并由"驱逐定时器(EvictionTimer)"定时调度,而启动"驱逐者线程"则由 BaseGenericObjectPool.startEvictor(long delay) 实现。

  • 大小: 36.6 KB
  • 大小: 58.7 KB
  • 大小: 28.2 KB
分享到:
评论

相关推荐

    Apache Commons Pool 2.4.1

    Apache Commons Pool 提供了一套完整的框架,允许开发者为各种类型的对象实现对象池。它包含了一些核心功能,如对象的创建、验证、工厂模式支持、池的大小控制、空闲对象的检测和清理等。以下是对Apache Commons ...

    commons-pool2-2.5.0-bin.zip

    5. **性能优化**:通过高效的并发控制和对象复用机制,Apache Commons Pool 2 在多线程环境中表现出优秀的性能。它使用了`java.util.concurrent`包中的并发工具,如`ReentrantLock`和`Semaphore`,确保了线程安全。 ...

    通过Apache common pool开源包实现对象池

    下面通过一个简单的样例来说明如何利用apache common pool来应用对象池。 假定我现在有一个任务,就是对一堆字符串进行格式化,为了加快速度,采用了多线程的方式允许,而格式化则是通过对象StringFormat来实现。 ...

    commons-pool.jar

    Apache Commons Pool的核心概念是对象池,它提供了一种机制,使得开发者可以定义一个对象工厂,用于创建和初始化对象,然后在需要时从池中获取,用完后归还回池,而不是直接销毁。这种方式提高了系统的效率,尤其是...

    Apache commons-pool2-2.4.2源码学习笔记

    通过分析这些图像和源码,我们可以了解到Apache Commons Pool2的内部工作机制,如对象的生命周期管理、池的配置和性能优化等方面的知识。此外,源码阅读也能帮助我们理解设计模式的应用,如工厂模式、池模式等,并能...

    commo-pool, commons-pool commons-pool commons-pool

    Apache Commons Pool 是一个Java对象池库,主要用于提供各种对象池化的实现,以便高效地管理和复用有限的资源。标题中的"commo-pool, commons-pool commons-pool commons-pool"可能是由于输入错误,正确的应该是...

    Apache common pool2 对象池

    Apache Commons Pool2 是一个强大的对象池库,广泛用于Java应用程序中,以提高性能和资源管理。对象池允许程序创建一组预先配置的对象,而不是每次需要时都创建新的对象,从而节省了初始化新对象的时间和系统资源。...

    commons-pool2-2.8.1.jar

    《Apache Commons Pool 2.8.1:高效对象池实现详解》 Apache Commons Pool 是一个广泛使用的开源组件,主要用于提供对象池化的实现。在Java世界里,对象池化是一种优化资源管理的重要技术,通过复用已创建的对象,...

    commons-pool-1.6.jar.zip

    Apache Commons Pool 是一个Java对象池库,主要用于提供各种对象池实现,以便在多个请求之间复用对象,从而提高性能和减少资源消耗。标题中的"commons-pool-1.6.jar.zip"表明这是一个包含Apache Commons Pool 1.6...

    commons-pool2-2.10.0.jar

    3. **对象池的创建与配置**:Apache Commons Pool 提供了多种预定义的对象池实现,如 `GenericObjectPool&lt;T&gt;` 和 `GenericKeyedObjectPool, K&gt;`,分别用于无键和有键的对象池。这些池可以通过配置参数进行定制,如...

    commons-pool commons-dbcp

    Apache Commons DBCP(Database Connection Pool)则是在Apache Commons Pool之上构建的一个数据库连接池实现。DBCP 1.4版本是这个库的一个稳定版本,它整合了Apache Commons Pool来管理数据库连接。DBCP提供了...

    commons-pool-1.5.5.jar.zip

    - **多类型支持**:Apache Commons Pool 支持多种类型的对象池,只需实现特定接口,即可实现自定义对象的池化。 - **线程安全**:所有操作都是线程安全的,可以在多线程环境中放心使用。 - **灵活配置**:可以...

    commons-pool2-2.0-API文档-中文版.zip

    Maven坐标:org.apache.commons:commons-pool2:2.0; 标签:apache、commons、pool2、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,...

    commons pool dbcp 包

    Apache Commons DBCP(Database Connection Pool)和Apache Commons Pool是两个在Java开发中常用的开源库,主要用于数据库连接池管理和对象池服务。它们是Apache软件基金会的项目,为Java应用程序提供了高效且可配置...

    commons-pool-1.4

    2. **基本对象池实现**:`GenericObjectPool` 是 Commons Pool 提供的主要对象池实现,它可以配置多种参数来优化性能和资源管理,如最大活动对象数、最大空闲对象数、空闲超时时间等。 3. **池化策略**:`...

    commons-pool.jar包下载

    2. **对象池实现**:除了API,Commons Pool还提供了一些预定义的对象池实现,如`GenericObjectPool`,这是一个通用的对象池实现,支持基本的池策略,如最大活动对象数、空闲对象的最大数量等。 3. **池化策略**:...

    commons-pool2-2.4.zip

    Apache Commons Pool2是一个Java对象池库,用于管理资源对象,如数据库连接或线程,以提高性能和效率。这个库的核心理念是通过复用已经创建的对象来减少对象的创建和销毁带来的开销,从而优化应用的性能。在"commons...

    commons-pool2-sr:Apache Commons Pool原始代码剖析笔记

    4. **配置参数**:Apache Commons Pool2允许用户自定义各种配置参数,如最大活动对象数、最大空闲对象数、空闲超时时间等,以适应不同应用场景的需求。 5. **对象生命周期管理**:Pool2提供了对象的生命周期管理...

    Apache的对象池化工具commons-pool

    ### Apache Commons Pool:Java对象池化技术详解 #### 一、引言 在现代软件开发过程中,尤其是在基于Java的企业级应用开发中,资源管理和优化变得尤为重要。创建和销毁对象的成本通常较高,特别是在高并发场景下,...

Global site tag (gtag.js) - Google Analytics