对象池

平时开发涉及到比如数据库连接、Redis连接等等其他连接,连接在创建、销毁的过程往往比较消耗资源、时间,于是,便出现连接池的概念。
其中不同的连接池都是保存着对象的,只不过有的对象是数据库连接对象,有的对象是Redis连接对象,由此可见,只要我们理解了对象池,则不同的池我们也掌握了原理。

我们基于apache开源的common-pools包来掌握对象池(GenericObjectPool)的原理。

对象池,主要有三个方法
一、borrowObject()
    借一个对象。
二、returnObject(T obj)
    归还对象,正常使用完对象后,归还对象。
三、invalidateObject(T obj)
    废弃对象,在使用对象过程中,对象出现异常(不是指我们的业务代码产生的异常),我们往往需要丢弃掉这个对象,调用这个方法,对象池就可以销毁该对象。

--idleObjects.hasTakeWaiters()获取当前有多少个线程阻塞着在等待空闲对象

一、borrowObject()

##获取池中的对象GenericObjectPool.borrowObject()##
在创建对象池时,我们可以设置阻塞blockWhenExhausted属性,默认为true。
根据是否阻塞?分两个不同策略
1.阻塞
从空闲队列取出队头元素,
如果取到的元素为null,则说明没空闲元素;创建一个对象
如果创建对象为null,则表示创建对象数量已经达到上限,只能阻塞直到空闲队列有可用的元素
进行阻塞:
    如果maxWaitMillis(毫秒)小于0则一直阻塞直到空闲队列有可用的元素;
    如果maxWaitMillis小于等于0则阻塞maxWaitMillis毫秒,从空闲队列取出头元素。
如果取到元素还是null,则抛出异常:等待空闲对象超时。
如果取到元素不是null,则调用boolean PooledObject.allocate()对对象进行分配
如果分配结果为false,则对象分配不成功,对象依然设为null
2.不阻塞
从空闲队列取出队头元素,
如果取到的元素为空,则说明没空闲元素;创建一个对象
如果创建对象为null,则表示创建对象数量已经达到上限,抛出异常:池的对象被全部用完。
如果取到元素不是null,则调用boolean PooledObject.allocate()对对象进行分配
如果分配结果为false,则对象分配不成功,对象依然设为null

通过1或者2取得对象元素,如果获取到对象不为null,执行下面操作:
调用PooledObjectFactory.activateObject(PooledObject<T> p)激活对象,如果activateObject抛出异常,则销毁对象p,且是新创建的对象则抛出异常:激活对象失败
激活对象后,如果testOnBorrow为true或者是新创建的对象且testOnCreate为true,则
调用boolean PooledObjectFactory.validateObject(PooledObject<T> p)验证对象是不是有效的、 可用的,如果验证为false,则销毁对象p,并确认空闲队列中至少有一个空闲对象(调用GenericObjectPool.ensureIdle(1, false) )

通过上面的过程后,如果对象为null,则循环上面步骤,直到获取对象不为null或者抛出异常;

最后调用方法updateStatsBorrow(p, System.currentTimeMillis() - waitTime)--待留
返回对象
/over.

二、returnObject(T obj)

##归还对象到池中GenericObjectPool.returnObject(T obj)##
从allObjects中获取封装对象的value对象(就是对象T obj的PooledObject对象,假设为p);
如果p为null,则说明已经被删除了,不做什么操作,直接返回结束方法;

加锁(p){
    如果p状态不是分配状态,则抛出异常:对象已经归还或不可用
    状态是分配状态,则调用PooledObject.markReturning()将p设置为正在归还状态。
}
if(testOnReturn){
    调用boolean PooledObjectFactory.validateObject(PooledObject<T> p)验证对象是不是可用的,如果验证为false,则销毁对象p,并确认空闲队列中至少有一个空闲对象(调用GenericObjectPool.ensureIdle(1, false) )
}
调用PooledObjectFactory.passivateObject(PooledObject<T> p) 钝化对象,调用有异常抛出则销毁对象p,并确认空闲队列中至少有一个空闲对象(调用GenericObjectPool.ensureIdle(1, false) )
调用PooledObject.deallocate()将自己设为空闲状态,设置失败则抛出异常:对象已经被归还或是不可用的
如果空闲对象数量不少于maxIdle,则不需要归还该对象,则销毁该对象;否则,根据lifo值将对象加入空闲队列的队头或队尾。
/over.

三、invalidateObject(T obj)

##废弃对象GenericObjectPool.invalidateObject(T obj)##
从allObjects中获取封装对象的value对象(就是对象T obj的PooledObject对象,假设为p);
如果p为null则抛出异常:对象已经不在池中;
否则,
加锁(p){
    检查p是不是INVALID状态,不是则销毁对象;是INVALID状态,则表示对象已经在销毁中,直接结束方法。
}
确认空闲队列中至少有一个空闲对象(调用GenericObjectPool.ensureIdle(1, false) )
/over.

++++++++++++++++++++++++++++++++++++++++++++++
GenericObjectPool<T>类
++++++++++++++++++++++++++++++++++++++++++++++

=================
创建一个对象
=================
PooledObject<T> create():
如果创建对象的数量已经大于maxTotal,或者大于int的最大值(2^31-1,2147483647),则对象数量达到上限,不能创建对象,返回null;
调用PooledObjectFactory<T>.makeOjbect()方法创建对象,如果创建失败,则抛出异常;
创建对象成功,则将新对象put进入allObjects(ConcurrentHashMap对象),返回新对象。
=================

=================
销毁对象
=================
destroy(PooledObject<T> toDestory):
对象调用PooledObject.invalidate()方法将自己作废,即将状态设为state = PooledObjectState.INVALID;
从空闲队列中删除该对象;
allObjects map中删除该对象;
调用工厂对象PooledObjectFactory.destroyObject(PooledObject<T> p)销毁对象,可以在这里释放相关资源等等工作。

=================
确认至少有idleCount个空闲对象
=================
void ensureIdle(int idleCount, boolean always):
always为true则表示不管有没有在阻塞等待的线程(idleObjects.hasTakeWaiters()),都会检查空闲对象的数量,否则,方法结束返回
如果空闲对象数量少于idleCount,则创建新对象放进空闲队列,根据lifo值来放进队列的队头或队尾。
++++++++++++++++++++++++++++++++++++++++++++++


++++++++++++++++++++++++++++++++++++++++++++++
PooledObject
++++++++++++++++++++++++++++++++++++++++++++++

=================
分配
=================
synchronized boolean allocate()://对象同步方法
如果对象状态为空闲PooledObjectState.IDLE,则
    修改状态为分配PooledObjectState.ALLOCATED,
    修改最近借时间和用时间lastBorrowTime = lastBorrowTime = now.
    对象借次数递增borrowedCount++;
    返回true;
如果对象状态为PooledObjectState.EVICTION(暂译:驱逐),则状态改为PooledObjectState.EVICTION_RETURN_TO_HEAD,返回false;
其他情况都返回false。

=================
归还
=================
void markReturning():
将状态设置归还
state = PooledObjectState.RETURNING;

++++++++++++++++++++++++++++++++++++++++++++++


四、源码

borrowObject

    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;
            if (blockWhenExhausted) {
                p = idleObjects.pollFirst();
                if (p == null) {
                    p = create();
                    if (p != null) {
                        create = true;
                    }
                }
                if (p == null) {
                    if (borrowMaxWaitMillis < 0) {
                        p = idleObjects.takeFirst();
                    } else {
                        p = idleObjects.pollFirst(borrowMaxWaitMillis,
                                TimeUnit.MILLISECONDS);
                    }
                }
                if (p == null) {
                    throw new NoSuchElementException(
                            "Timeout waiting for idle object");
                }
                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;
                }
            }

            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())) {
                    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(T obj)

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) {
            final PooledObjectState state = p.getState();
            if (state != PooledObjectState.ALLOCATED) {
                throw new IllegalStateException(
                        "Object has already been returned to this pool or is invalid");
            } else {
                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);
            }
            updateStatsReturn(activeTime);
            return;
        }

        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()) {
            try {
                destroy(p);
            } catch (Exception e) {
                swallowException(e);
            }
        } else {
            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);
    }

invalidateObject(T obj)

public void invalidateObject(T obj) throws Exception {
        PooledObject<T> p = allObjects.get(new IdentityWrapper<T>(obj));
        if (p == null) {
            if (isAbandonedConfig()) {
                return;
            } else {
                throw new IllegalStateException(
                        "Invalidated object not currently part of this pool");
            }
        }
        synchronized (p) {
            if (p.getState() != PooledObjectState.INVALID) {
                destroy(p);
            }
        }
        ensureIdle(1, false);
    }

..


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值