apache commons-pool是apache基金会的一个开源对象池组件,咱们经常使用的数据库链接池dpcp和redis的java客户端jedis都使用commons-pool来管理链接java
优化对象的建立,和设计模式中的享元模式思路同样git
PooledObject 池化后的对象github
ObjectPool 对象池,redis
PooledObjectFactory 池对象工厂数据库
GenericObjectPoolapache
实现了对对象池的管理,是一个基本的对象池实现
borrowObject
从对象池中获取一个对象
returnObject
对象使用完以后,归还到对象池segmentfault
PooledObjectFactory设计模式
根据本身的业务建立和管理要对象池化的对象
makeObject
建立对象
destroyObject
销毁对象缓存
validateObject
检测一个对象是否有效,无效会被销毁
activateObject
激活一个对象或者说启动对象的某些操做socket
borrowObject
的时候passivateObject
钝化对象
在向对象池归还一个对象是会调用这个方法。这里能够对对象作一些清理操做。好比清理掉过时的数据,下次得到对象时,不受旧数据的影响
通常来讲activateObject和passivateObject是成对出现的。前者是在对象从对象池取出时作一些操做,后者是在对象归还到对象池作一些操做,能够根据本身的业务须要进行取舍。
参数配置类GenericObjectPoolConfig
lifo: 对象池存储空闲对象是使用的LinkedBlockingDeque,建议使用默认值true
fairness: 是否使用lock的公平锁(不公平的性能高5-10倍,获取锁时没排队,没有先到先得的概念)。默认值是false,建议使用默认值。
maxWaitMillis: 当没有空闲链接时,获取一个对象的最大等待时间。若是这个值小于0,则永不超时,一直等待,直到有空闲对象到来。若是大于0,则等待maxWaitMillis长时间,若是没有空闲对象,将抛出NoSuchElementException异常。默认值是-1;能够根据须要本身调整,单位是毫秒。
minEvictableIdleTimeMillis: 当空闲的时间大于这个值时,执行移除这个对象操做,默认值30分钟。这个参数是强制性的,只要空闲时间超过这个值,就会移除.小于0则为Long的最大值
softMinEvictableIdleTimeMillis: 对象最小的空闲时间 ,和minEvictableIdleTimeMillis
逻辑同样,区别是:它会保留最小的空闲对象数量。而上面的不会,是强制性移除的。默认值是-1;
numTestsPerEvictionRun: 检测空闲对象线程每次检测的空闲对象的数量。默认值是3;若是这个值小于0,则每次检测的空闲对象数量等于当前空闲对象数量除以这个值的绝对值,并对结果向上取整
testOnCreate: 在建立对象时检测对象是否有效,true是,默认值是false。
testOnBorrow: 在从对象池获取对象时是否检测对象有效,true是;默认值是false。
testOnReturn: 在向对象池中归还对象时是否检测对象有效,true是,默认值是false。
testWhileIdle: 在检测空闲对象线程检测到对象不须要移除时,是否检测对象的有效性。true是,默认值是false。
timeBetweenEvictionRunsMillis:空闲对象检测线程的执行周期,即多长时候执行一次空闲对象检测。单位是毫秒数。若是小于等于0,则不执行检测线程。默认值是-1;
blockWhenExhausted: 当对象池没有空闲对象时,新的获取对象的请求是否阻塞。true阻塞。默认值是true;
maxTotal:对象池中管理的最多对象个数。默认值是8。
maxIdle:对象池中最大的空闲对象个数。默认值是8。
minIdle:对象池中最小的空闲对象个数。默认值是0。
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.3</version> </dependency>
public class Resource { private static int id; private int rid; public Resource() { synchronized (this) { this.rid = id++; } } public int getRid() { return this.rid; } @Override public String toString() { return "id:" + this.rid; } }
public class MyPoolableObjectFactory extends BasePooledObjectFactory<Resource>{ /** * 建立一个对象实例 */ @Override public Resource create() throws Exception { return new Resource(); } /** * 包裹建立的对象实例,返回一个pooledobject */ @Override public PooledObject<Resource> wrap(Resource obj) { return new DefaultPooledObject<Resource>(obj); } }
public class Test { public static void main(String[] args) { // 建立池对象工厂 PooledObjectFactory<Resource> factory = new MyPoolableObjectFactory(); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // 最大空闲数 poolConfig.setMaxIdle(5); // 最小空闲数, 池中只有一个空闲对象的时候,池会在建立一个对象,并借出一个对象,从而保证池中最小空闲数为1 poolConfig.setMinIdle(1); // 最大池对象总数 poolConfig.setMaxTotal(20); // 逐出链接的最小空闲时间 默认1800000毫秒(30分钟) poolConfig.setMinEvictableIdleTimeMillis(1800000); // 逐出扫描的时间间隔(毫秒) 若是为负数,则不运行逐出线程, 默认-1 poolConfig.setTimeBetweenEvictionRunsMillis(1800000 * 2L); // 在获取对象的时候检查有效性, 默认false poolConfig.setTestOnBorrow(true); // 在归还对象的时候检查有效性, 默认false poolConfig.setTestOnReturn(false); // 在空闲时检查有效性, 默认false poolConfig.setTestWhileIdle(false); // 最大等待时间, 默认的值为-1,表示无限等待。 poolConfig.setMaxWaitMillis(5000); // 是否启用后进先出, 默认true poolConfig.setLifo(true); // 链接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true poolConfig.setBlockWhenExhausted(true); // 每次逐出检查时 逐出的最大数目 默认3 poolConfig.setNumTestsPerEvictionRun(3); // 建立对象池 final GenericObjectPool<Resource> pool = new GenericObjectPool<Resource>(factory, poolConfig); for (int i = 0; i < 40; i++) { new Thread(new Runnable() { @Override public void run() { try { Resource resource = pool.borrowObject();// 注意,若是对象池没有空余的对象,那么这里会block,能够设置block的超时时间 System.out.println(resource); Thread.sleep(1000); pool.returnObject(resource);// 申请的资源用完了记得归还,否则其余人要申请时可能就没有资源用了 } catch (Exception e) { e.printStackTrace(); } } }).start(); } } }
例二:
/** * FileName :Conn * Author :zengzhijun * Date : 2018/5/30 19:41 * Description: */ package com.byedbl.pool.example1; import org.slf4j.LoggerFactory; /** * common-pool2 使用方式 * <p/> * 假设这是一个创建TCP链接的对象,该对象的初始化时间平均为500ms,为了不在程序中频繁建立Conn对象,咱们须要借助对象池管理Conn对象实例 * * @author : zengzhijun * @date : 2018/5/30 19:42 **/ public class Conn { /** * 记录对象的建立时间 */ private long createTime; /** * 初始化Conn对象,模拟建立Conn对象平均消耗500ms * @throws InterruptedException */ public Conn() throws InterruptedException { Thread.sleep(500); createTime = System.currentTimeMillis(); LoggerFactory.getLogger(getClass()).debug(" init conn suc... " + createTime); } /** * 报告Conn对象信息 */ public void report() { LoggerFactory.getLogger(getClass()).info("this is a available conn " + createTime); } }
/** * FileName :ConnFactory * Author :zengzhijun * Date : 2018/5/30 19:46 * Description: */ package com.byedbl.pool.example1; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; /** * common-pool2 使用方式 * <p/> * 为了使用common-pool2对象池管理,咱们必须实现{@link org.apache.commons.pool2.PooledObjectFactory}或者其子类 * 这是一个工厂模式,告诉对象池怎样去建立要管理的对象 * <p/> * BasePooledObjectFactory 是对{@link org.apache.commons.pool2.PooledObjectFactory}的一个基本实现,咱们能够继承该类,减小一些方法的实现 * <p/> * 在实现{@link org.apache.commons.pool2.PooledObjectFactory}接口时,咱们必定要实现的接口方法是{@link org.apache.commons.pool2.PooledObjectFactory#makeObject()}方法。 * * @author : zengzhijun * @date : 2018/5/30 19:46 **/ public class ConnFactory extends BasePooledObjectFactory<Conn> { /** * 间接实现{@link org.apache.commons.pool2.PooledObjectFactory#makeObject()}方法,代表怎样建立须要管理对象 */ @Override public Conn create() throws Exception { return new Conn(); } /** * 在common-pool2中为了统计管理的对象的一些信息,好比调用次数,空闲时间,上次使用时间等,须要对管理的对象进行包装,而后在放入到对象池中 * * @param obj 对象池要管理的对象 * @return 返回包装后的PooledObject对象 */ @Override public PooledObject<Conn> wrap(Conn obj) { return new DefaultPooledObject<Conn>(obj); } }
/** * FileName :ConnPool * Author :zengzhijun * Date : 2018/5/30 19:51 * Description: */ package com.byedbl.pool.example1; import org.apache.commons.pool2.impl.GenericObjectPool; /** * common-pool2 使用方式 * <p/> * Conn对象管理池,这里利用 GenericObjectPool 做为对象池 * * @author : zengzhijun * @date : 2018/5/30 19:52 **/ public class ConnPool extends GenericObjectPool<Conn> { /** * 调用{@link GenericObjectPool}的构造方法,构造ConnPool */ public ConnPool() { super(new ConnFactory(), new ConnPoolConfig()); } /** * 调用{@link GenericObjectPool}的构造方法,构造ConnPool */ public ConnPool(ConnPoolConfig connPoolConfig) { super(new ConnFactory(), connPoolConfig); } }
/** * FileName :ConnPoolConfig * Author :zengzhijun * Date : 2018/5/30 19:50 * Description: */ package com.byedbl.pool.example1; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; /** * common-pool2 使用方式 * <p/> * {@link org.apache.commons.pool2.impl.GenericObjectPool}支持个性化配置,咱们能够配置对象池中总共的对象数,最大、最小空闲对象数等等 * 这边继承{@link GenericObjectPoolConfig}是为了ConnPool也能够进行个性化的配置 * * @author : zengzhijun * @date : 2018/5/30 19:50 **/ public class ConnPoolConfig extends GenericObjectPoolConfig { public ConnPoolConfig() { // defaults to make your life with connection pool easier :) setMinIdle(5); setTestOnBorrow(true); } }
package com.byedbl.pool.example1; import org.junit.Test; public class ConnPoolTest { @Test public void conn() throws Exception { ConnPoolConfig connPoolConfig = new ConnPoolConfig(); connPoolConfig.setMinIdle(5); connPoolConfig.setMaxIdle(8); ConnPool connPool = new ConnPool(connPoolConfig); Conn conn1 = connPool.borrowObject(); Conn conn2 = connPool.borrowObject(); Conn conn3 = connPool.borrowObject(); Conn conn4 = connPool.borrowObject(); Conn conn5 = connPool.borrowObject(); conn1.report(); connPool.returnObject(conn1); conn2.report(); connPool.returnObject(conn2); conn3.report(); connPool.returnObject(conn3); conn4.report(); connPool.returnObject(conn4); conn5.report(); connPool.returnObject(conn5); conn5.report(); // 被归还的对象的引用,不能够在次归还 // java.lang.IllegalStateException: Object has already been retured to this pool or is invalid try { connPool.returnObject(conn5); }catch (Exception e){ e.printStackTrace(); } } }
common-pool2链接池详解与使用
common-pool2 使用
使用示例源码
一个FTP的工具工程
thrift-client-manager
apache-common-pool2源码分析
commons-pool2源码分析
做者:巨子联盟 连接:https://www.jianshu.com/p/f403f1782d1c 来源:简书 简书著做权归做者全部,任何形式的转载都请联系做者得到受权并注明出处。