对象池
来源:互联网 发布:淘宝怎么打印发货单 编辑:程序博客网 时间:2024/05/16 15:44
平时开发涉及到比如数据库连接、Redis连接等等其他连接,连接在创建、销毁的过程往往比较消耗资源、时间,于是,便出现连接池的概念。
其中不同的连接池都是保存着对象的,只不过有的对象是数据库连接对象,有的对象是Redis连接对象,由此可见,只要我们理解了对象池,则不同的池我们也掌握了原理。
我们基于apache开源的common-pools包来掌握对象池(GenericObjectPool)的原理。
对象池,主要有三个方法
一、borrowObject()
借一个对象。
二、returnObject(T obj)
归还对象,正常使用完对象后,归还对象。
三、invalidateObject(T obj)
废弃对象,在使用对象过程中,对象出现异常(不是指我们的业务代码产生的异常),我们往往需要丢弃掉这个对象,调用这个方法,对象池就可以销毁该对象。
--idleObjects.hasTakeWaiters()获取当前有多少个线程阻塞着在等待空闲对象
在创建对象池时,我们可以设置阻塞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.
从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.
从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
..
其中不同的连接池都是保存着对象的,只不过有的对象是数据库连接对象,有的对象是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
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- 对象池
- Django-HttpResponse返回models对象
- FastDFS在.Net平台上的使用
- java.math.BigInteger cannot be cast to java.lang.Long
- Python3的循环
- C++实验3-个人所得税计算器
- 对象池
- iOS KVC和KVO的使用
- 使用自定义的类作为Map接口key的参数时
- 【面试题12】打印1到最大的n位数
- namespace
- C++上机实验3—(4)
- 常用命令汇总
- android 6.0以后的运行时权限申请及封装 相关记录
- mongodb API 官方资料