对象池

来源:互联网 发布:淘宝怎么打印发货单 编辑:程序博客网 时间:2024/05/16 15:44
平时开发涉及到比如数据库连接、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);    }

..


0 0
原创粉丝点击