类图关系
为了简单起见,该图只表现继承和实现关系
大部分情况下我们只使用ObjectPool和PoolableObjectFactory的相关实现类,我们重点分析GenricObjectPool类
配置参数
类GenericObjectPool.Config定义了相关参数:
从池中获取对象
从池中获取对象有borrowObject()方法负责,那么该方法到底做了什么?
我们可以看到borrowObject方法中又很多地方都调用了一个内部函数allocate(),
该方法主要负责为每一个请求(latch)分配对象,具体实现如下:
未完待续...
为了简单起见,该图只表现继承和实现关系
大部分情况下我们只使用ObjectPool和PoolableObjectFactory的相关实现类,我们重点分析GenricObjectPool类
配置参数
类GenericObjectPool.Config定义了相关参数:
// 池中最大空闲实例个数 int maxIdle=8 // 池中最小空闲实例个数 (evictor会用到) int minIdle=0 // 可以从池中拿走的最多实例的个数,就是通常我们说的池大小 // 小于0则代表没有限制 int maxActive=8 // 当池耗尽并且whenExhaustedAction的值是WHEN_EXHAUSTED_BLOCK时候, // borrowObject方法最大等待时间(毫秒),超过改时间则抛出异常 // (意思就是当池被耗尽时,从池中获取对象要等的时间) // 小于0时一直阻塞 long maxWait = -1 // 当池被耗尽时,borrowObject方法应该采取的措施 byte whenExhaustedAction = WHEN_EXHAUSTED_BLOCK // 默认是false,当是true得时候,borrowObject方法在返回之前 // 会调用自定义的PoolableObjectFactory.validateObject方法,校验 // 要返回的对象是否可用.如果不可用,该对象会被销毁,然后 // 会尝试生成另一个对象. boolean testOnBorrow = false // 默认是false,当时true的时候,当调用retruenObject将对象放回 // 池中时会调用PoolableObjectFactory.validateObject方法,校验对象 // 是否可用. (如果不可用会销毁该对象) boolean testOnReturn = false // 默认是fasle,当是true时,闲置对象驱逐器会调用validateObject // 方法,校验对象是否可用,如果不可用会将其从池中drop掉 boolean testWhileIdle = false // 闲置对象驱逐器运行的间隔时间(毫秒),如果是非正数则驱逐器将不会运行. // (驱逐器可以确保池内对象不小于minIdle) long timeBetweenEvictionRunsMillis = -1 // 驱逐器每次运行时检查池中闲置对象的最大个数 // (比如该值设置为3,此时池中有5个闲置对象,那么每次只会检查前三个闲置对象。 // 比如检查闲置对象是否可用等。ensureMinIdle()不受这个影响,因为是做完检查 // 后才执行ensureMinIdle) int numTestsPerEvictionRun = 3 // 一个对象可以停留在池中的最少闲置时间,如果该对象在池中 // 的闲置时间大于该值,那么该对象就可以被驱逐器dorp掉。 // 如果是非正数,表示该对象可以一直闲置下去。(单位毫秒) long minEvictableIdleTimeMillis = 1000L * 60L * 30L // 和minEvictableIdleTimeMillis作用一样,但有一个额外条件: // 如果池中闲置对象的个数不大于minIdle时,即使有对象的 // 闲置时间大于该设置的值也不会被dorp掉. // 注意:如果minEvictableIdleTimeMillis>0则该参数就不在起作用. long softMinEvictableIdleTimeMillis = -1 // 默认LIFO状态.true的意思是borrowObject方法返回池中的最近 // 使用过的闲置对象(如果该实例可用). fasle的意思是池是一个 // FIFO队列--对象从池中顺序的返回. boolean lifo = true
从池中获取对象
从池中获取对象有borrowObject()方法负责,那么该方法到底做了什么?
public T borrowObject() throws Exception { long starttime = System.currentTimeMillis(); Latch<T> latch = new Latch<T>(); //代表一个请求 byte whenExhaustedAction; long maxWait; synchronized (this) { // Get local copy of current config. Can't sync when used later as // it can result in a deadlock. Has the added advantage that config // is consistent for entire method execution whenExhaustedAction = _whenExhaustedAction; maxWait = _maxWait; // Add this request to the queue // 请这个请求放入到请求对列.由下面的allocate()方法进行分配 _allocationQueue.add(latch); } // Work the allocation queue, allocating idle instances and // instance creation permits in request arrival order //操作分配队列 ,为请求顺序分配空闲实例和实例创建许可 allocate(); for(;;) { synchronized (this) { assertOpen(); } // If no object was allocated from the pool above // 没有从池中分配出一个池对象 if(latch.getPair() == null) { // check if we were allowed to create one // 检查是否允许创建一个池对象 if(latch.mayCreate()) { // allow new object to be created // 允许创建一个池对象 } else { // the pool is exhausted // 池被耗尽时执行以下耗尽策略 switch(whenExhaustedAction) { case WHEN_EXHAUSTED_GROW: //该策略可以忽略不能创建新池对象的限制 // allow new object to be created synchronized (this) { // Make sure another thread didn't allocate us an object // or permit a new object to be created // 确保这是其他线程没有给当前请求(latch)关联一个池对象 // 或者授权可创建新对象 if (latch.getPair() == null && !latch.mayCreate()) { //将请求从请求队列中移除,这时该请求就变为可用请求 _allocationQueue.remove(latch); _numInternalProcessing++; } } break; case WHEN_EXHAUSTED_FAIL: //该策略直接抛异常 synchronized (this) { // Make sure allocate hasn't already assigned an object // in a different thread or permitted a new object to // be created if (latch.getPair() != null || latch.mayCreate()) { break; } _allocationQueue.remove(latch); } throw new NoSuchElementException("Pool exhausted"); case WHEN_EXHAUSTED_BLOCK: //该策略让请求等待一段时间 try { // 该同步块用latch作为锁原因: // 1.和allocate()方法中的latch同步块配合; // 2.减小锁的范围,如果都用this锁,那么走到这里时所有的线程都要 // 顺序执行,但是用latch就不用,因为各个线程持有的锁(latch)不一样 // 所以这里对不同的线程可以并发执行。 synchronized (latch) { // Before we wait, make sure another thread didn't // allocate us an object // or permit a new object to be created // 等待之前确保其他线程没有给分配一个池对象或授权创建新池对象 if (latch.getPair() == null && !latch.mayCreate()) { if(maxWait <= 0) { //最大等待时间小于等于0就一直等待 latch.wait(); } else { //计算需要等待的时间并执行等待 // this code may be executed again after a // notify then continue cycle // so, need to calculate the amount of time //to wait final long elapsed = (System.currentTimeMillis() - starttime); final long waitTime = maxWait - elapsed; if (waitTime > 0){ latch.wait(waitTime); } } } else { break; } } // see if we were awakened by a closing pool if(isClosed() == true) { throw new IllegalStateException("Pool closed"); } } catch(InterruptedException e) { //被其他线程提前中断 boolean doAllocate = false; synchronized(this) { // Need to handle the all three possibilities // 需要处理三种可能性 if (latch.getPair() == null && !latch.mayCreate()) { // Case 1: latch still in allocation queue // Remove latch from the allocation queue // 情况1:请求仍然在请求队列,还没有分配池对象 _allocationQueue.remove(latch); } else if (latch.getPair() == null && latch.mayCreate()) { //Case 2:latch has been given permission to create // a new object //情况2:请求已经被赋予可以创建新池对象 _numInternalProcessing--; //腾出一个坑儿,让给别人 doAllocate = true; } else { // Case 3: An object has been allocated // 情况3:请求已经分配了一个池对象 _numInternalProcessing--; //下面的returnObject方法会将该值减一,所以这里先加一 _numActive++; //以上两句可以理解为将关联池对象返回给了外部 //而这语句表示将外部的池对象放入到池中 returnObject(latch.getPair().getValue()); } } if (doAllocate) { allocate(); } //发生中断异常后,中断状态已经被清除. //重置线程中断状态 Thread.currentThread().interrupt(); //? throw e; } // 如果线程等待超时、产生虚假唤醒(没有被通知、中断或超时) // 或者其他线程调用latch.notify则会走到这一步 if(maxWait > 0 && ((System.currentTimeMillis() - starttime) >= maxWait)) {// 超时 synchronized(this) { // Make sure allocate hasn't already assigned an object // in a different thread or permitted a new object to // be created //超时后仍没有获取到一个关联池对象或者新创建许可 if (latch.getPair() == null && !latch.mayCreate()) { // Remove latch from the allocation queue _allocationQueue.remove(latch); } else {//在等待的过程中获取到一个关联池对象或者新创建许可 break; } } throw new NoSuchElementException("Timeout waiting "+ "for idle object"); } else { //虚假唤醒或其它线程调用了latch.notify continue; // keep looping } default: throw new IllegalArgumentException("WhenExhaustedAction property " + whenExhaustedAction +" not recognized."); } } } // 走到这里说明允许创建一个新池对象或者已经关联了一个池对象 boolean newlyCreated = false; //是否已经创建了池对象 if(null == latch.getPair()) { //没有关联一个吃对象,但是允许创建一个池对象 try { T obj = _factory.makeObject(); latch.setPair(new ObjectTimestampPair<T>(obj)); //关联池对象 newlyCreated = true; } finally { if (!newlyCreated) {//池对象创建失败 //object cannot be created //因为之前在allocate()方法中在设置_mayCreate值时 //将_numInternalProcessing++ //所以如果创建池对象失败就将可用请求个数减一 synchronized (this) { _numInternalProcessing--; // No need to reset latch - about to throw exception } // 腾出来一个坑儿,让给其他人 allocate(); } } } // activate & validate the object // 走到这里说明已经获取到了一个池对象(新创建的或者从池中拿的) // 激活和校验池对象是否可用 try { _factory.activateObject(latch.getPair().value); //只有_testOnBorrow值为true时才对关联的池对象进行校验 if(_testOnBorrow && !_factory.validateObject(latch.getPair().value)) { throw new Exception("ValidateObject failed"); } //池对象返回给外部前,可用请求个数减一,池外活跃对象个数加一 synchronized(this) { _numInternalProcessing--; _numActive++; } //返回池对象 return latch.getPair().value; } catch (Throwable e) { //?? PoolUtils.checkRethrow(e);//?? // object cannot be activated or is invalid // 池对象不能被激活或者校验失败 try { _factory.destroyObject(latch.getPair().value); } catch (Throwable e2) { PoolUtils.checkRethrow(e2); // cannot destroy broken object } synchronized (this) { _numInternalProcessing--; // 请求已关联到一个池对象,但是池对象不可用 if (!newlyCreated) { //重置请求,并将该请求放入到请求队列 //后续再调用一次allocate()方法继续从池中拿空闲对象 latch.reset(); _allocationQueue.add(0, latch); } } allocate(); //走到这里并且newlyCreated=true //那么说明池中已经没有空闲对象,并且新创建的池对象不可用,那么直接抛异常 if(newlyCreated) { throw new NoSuchElementException("Could not create a validated "+ "object,"+ " cause: " + e.getMessage()); //走到这里且newlyCreated=false //说明请求(latch)从池中获取的对象不可用,那么继续循环从池中寻找空闲对象 //如果池中没有空闲对象并且也不允许再创建新池对象, //那么会进入池耗尽策略switch(whenExhaustedAction)代码块 }else { continue; // keep looping } } } }
我们可以看到borrowObject方法中又很多地方都调用了一个内部函数allocate(),
该方法主要负责为每一个请求(latch)分配对象,具体实现如下:
private synchronized void allocate() { if (isClosed()) return; // First use any objects in the pool to clear the queue // 首先,用池中的对象给请求队列中的请求分配对象 for (;;) { //如果有请求队列有请求,且池中又空闲对象 if (!_pool.isEmpty() && !_allocationQueue.isEmpty()) { Latch<T> latch = _allocationQueue.removeFirst(); latch.setPair( _pool.removeFirst()); //从池中拿走一个对象给请求(latch) _numInternalProcessing++; //正在分配中得对象的个数 synchronized (latch) { //当池中对象已经耗尽且when_exhausted_block值是WHEN_EXHAUSTED_BLOCK //这个时候来的请求会根据过期时间在同步块中等待。 //这语句让让等待(latch.wait(xxx))的请求激活 latch.notify(); } } else { //跳出,直到将池中得对象分配完毕 break; } } // Second any spare capacity to create new objects // 然后,根据池的配置决定是否可以为请求队列中的请求(latch)创建新的池对象 for(;;) { //_maxActive 最大活跃对象个数 //_numActive 当前在池外的活跃对象个数 //_numInternalProcessing 可用请求(已分配池对象或_mayCreate标记为true的latch)的个数 if((!_allocationQueue.isEmpty()) && (_maxActive < 0 || (_numActive + _numInternalProcessing) < _maxActive)) { Latch<T> latch = _allocationQueue.removeFirst(); latch.setMayCreate(true); //设置该请求(latch)的可创建标志为true _numInternalProcessing++; synchronized (latch) { //通知等待的latch可以创建池对象了 latch.notify(); } } else { break; } } }
未完待续...
相关推荐
赠送jar包:commons-pool-1.6.jar; 赠送原API文档:commons-pool-1.6-javadoc.jar; 赠送源代码:commons-pool-1.6-sources.jar; 赠送Maven依赖信息文件:commons-pool-1.6.pom; 包含翻译后的API文档:commons-...
都是自己项目积累下来的jar 真正的好用的jar 第一:commons-pool-1.3.jar 第二:commons-pool-1.5.4.jar 第三:commons-pool-1.6.jar 第四:commons-pool2-2.1.jar
标题中的"commons-pool-1.6.jar.zip"表明这是一个包含Apache Commons Pool 1.6版本的压缩文件,其中的核心组件是`commons-pool-1.6.jar`。 **Apache Commons Pool 概述** Apache Commons Pool 是Apache软件基金会的...
"commons-pool-1.6.jar" 这个文件名表明它是一个Java库,属于Apache Commons项目的一部分,具体是Apache Commons Pool 1.6版本。Apache Commons Pool是一个通用的对象池服务,它提供了一种有效管理对象资源的方式,...
标题 "jedis-2.1.0.jar+commons-pool-1.6.jar" 提供了两个关键组件的信息:Jedis 和 Commons Pool。这两个库在Java开发中常用于与Redis数据库进行交互。Jedis是Java的一个开源客户端,专门用于操作Redis,而Commons ...
Apache Commons DBCP 1.4 和 Apache Commons Pool 1.6 是两个在Java应用程序中广泛使用的开源库,主要用于数据库连接池的管理。这两个库在处理大量并发数据库访问时能够提高性能并优化资源利用。 Apache Commons ...
commons-pool-1.3.jar+commons-pool.jar;java连接池jar包java连接池;java连接池jar;commons-pool-1.2.jar;commons-pool-1.3.jar+commons-pool.jar;java连接池jar包java连接池;java连接池jar;commons-pool-1.2.jar;...
commons-pool-1.6.jar 注:需要重启Jmeter才会生效; commons-pool.jar包是一款常用在java开发内的进行java数据库连接池的框架常用包,如果您想对java开发进行数据库连接池,可以前来下载这款commons-pool.jar包使用...
commons-pool-1.6-javadoc.jar, commons-pool-1.6-sources.jar, commons-pool-1.6.jar, commons-pool-20030825.183949.jar, commons-pool-osgi-1.3.0.jar, commons-pool.jar, commons-pool2-2.4.2-javadoc.jar, ...
开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发工具 commons-pool2-2.4.2开发...
赠送jar包:commons-pool2-2.0.jar; 赠送原API文档:commons-pool2-2.0-javadoc.jar; 赠送源代码:commons-pool2-2.0-sources.jar; 赠送Maven依赖信息文件:commons-pool2-2.0.pom; 包含翻译后的API文档:...
3. `commons-pool-1.6.jar`:Apache Commons Pool是通用的对象池服务,它是DBCP连接池依赖的基础。DBCP利用了Pool库来实现对象(这里是数据库连接)的池化管理,包括创建、分配、回收和销毁连接等操作。 使用DBCP...
这两个JAR文件,`commons-dbcp-1.4.jar` 和 `commons-pool-1.5.6.jar`,在Java应用中起到了重要的角色,特别是对于那些需要高效管理数据库连接的大型系统。 Apache Commons DBCP是Apache Commons项目的一部分,它...
赠送jar包:commons-pool2-2.3.jar; 赠送原API文档:commons-pool2-2.3-javadoc.jar; 赠送源代码:commons-pool2-2.3-sources.jar; 赠送Maven依赖信息文件:commons-pool2-2.3.pom; 包含翻译后的API文档:...
赠送jar包:commons-pool2-2.10.0.jar; 赠送原API文档:commons-pool2-2.10.0-javadoc.jar; 赠送源代码:commons-pool2-2.10.0-sources.jar; 赠送Maven依赖信息文件:commons-pool2-2.10.0.pom; 包含翻译后的API...
赠送jar包:commons-pool2-2.10.0.jar; 赠送原API文档:commons-pool2-2.10.0-javadoc.jar; 赠送源代码:commons-pool2-2.10.0-sources.jar; 赠送Maven依赖信息文件:commons-pool2-2.10.0.pom; 包含翻译后的API...
Apache Commons Pool 1.6是Java开发中一个重要的工具库,专门用于对象池化服务。对象池化是一种优化资源管理的技术,它通过预先创建并维护一组可重用对象,避免了频繁的对象创建和销毁,从而提高了系统性能。在...
赠送jar包:commons-pool2-2.5.0.jar; 赠送原API文档:commons-pool2-2.5.0-javadoc.jar; 赠送源代码:commons-pool2-2.5.0-sources.jar; 包含翻译后的API文档:commons-pool2-2.5.0-javadoc-API文档-中文...
DBCP(DataBase Connection Pool)是 apache common上的一个 java 连接池项目,也是 tomcat 使用的连接池组件,依赖 于Jakarta commons-pool 对象池机制,DBCP可以直接的在应用程序中使用。 使用DBCP会用到commons-...