apache commons pool

apache commons下的pool

其中的borrowObject函数源代码显示其产生可用对象的过程:

    若是stack中有空闲的对象,则pop对象,激活对象(activate函数),验证对象(validate函数)。最终将合格的对象返回给client。sql

                       若对象在这个流程中出错,则在从stack中取出一个,并执行相同的流程。如此循环,直到stack为空。数据库

    若是stack为空,则直接调用makeObject函数建立一个对象。在返回对象以前,还会调用验证函数(validate)验证是否有效。apache

转载:

Apache common-pool, common-dbcp源码解读与对象池原理剖析 【转载】

博客分类:

最近在作一个内部测试工具类的优化工做中接触到了链接池, 对象池技术, 将原有的未使用链接池的数据库访问操做改为链接池方式.性能有了很是大的提高, 事实证实, 通过两次改造, 原来一个比较大的测试类须要500多秒, 第一次优化后只须要300多秒, 第二次改用链接池以后同一个测试类只须要80多秒.下面是改造过程当中的一些总结.
对象池就是以"空间换时间"的一种经常使用缓存机制, 这里的"时间"特指建立时间,所以这也给出了对象池的适用范围:若是一种对象的建立过程很是耗时的话, 那么请使用对象池. 内部原理简单的说, 就是将建立的对象放到一个容器中, 用完以后不是销毁而是再放回该容器, 让其余的对象调用, 对象池中还涉及到一些高级的技术, 好比过时销毁, 被破坏时销毁, 对象数超过池大小销毁, 对象池中没有可用空闲对象时等待等等.

apache的common-pool工具库是对池化技术原理的一种具体实现. 在阐述原来以前, 这里先理解几个概念: 
对象池(ObjectPool接口): 能够把它认为是一种容器, 它是用来装池对象的, 而且包含了用来建立池对象的工厂对象 
池对象:就是要放到池容器中的对象, 理论上能够是任何对象. 
对象池工厂(ObjectPoolFactory接口):用来建立对象池的工厂, 这个没什么好说的. 
池对象工厂(PoolableObjectFactory接口):用来建立池对象, 将不用的池对象进行钝化(passivateObject), 对要使用的池对象进行激活(activeObject), 对池对象进行验证(validateObject), 对有问题的池对象进行销毁(destroyObject)等工做

对象池中封装了建立, 获取, 归还, 销毁池对象的职责, 固然这些工做都是经过池对象工厂来实施的, 容器内部还有一个或多个用来盛池对象的容器.对象池会对容器大小, 存放时间, 访问等待时间, 空闲时间等等进行一些控制, 由于能够根据须要来调整这些设置.

当须要拿一个池对象的时候, 就从容器中取出一个, 若是容器中没有的话, 并且又没有达到容器的最大限制, 那么就调用池对象工厂, 新建一个池对象, 并调用工厂的激活方法, 对建立的对象进行激活, 验证等一系列操做. 若是已经达到池容器的最大值, 而对象池中又经没有空闲的对象, 那么将会继续等待, 直到有新的空闲的对象被丢进来, 固然这个等待也是有限度的, 若是超出了这个限度, 对象池就会抛出异常.

"出来混, 老是要还的", 池对象也是如此, 当将用完的池对象归还到对象池中的时候, 对象池会调用池对象工厂对该池对象进行验证, 若是验证不经过则被认为是有问题的对象, 将会被销毁, 一样若是容器已经满了, 这个归还池对象将变的"无家可归", 也会被销毁, 若是不属于上面两种状况, 对象池就会调用工厂对象将其钝化并放入容器中. 在整个过程当中, 激活, 检查, 钝化处理都不是必须的, 所以咱们在实现PoolableObjectFactory接口的时候, 通常不做处理, 给空实现便可, 因此诞生了BasePoolableObjectFactory.

固然你也能够将要已有的对象建立好, 而后经过addObject放到对象池中去, 以备后用. 

为了确保对对象池的访问都是线程安全的, 全部对容器的操做都必须放在synchronized中. 

在apache的common-pool工具库中有5种对象池:GenericObjectPool和GenericKeyedObjectPool, SoftReferenceObjectPool, StackObjectPool, StackKeyedObjectPool.
五种对象池可分为两类, 一类是无key的: 
缓存


另外一类是有key的: 
安全

前面两种用CursorableLinkedList来作容器, SoftReferenceObjectPool用ArrayList作容器, 一次性建立全部池化对象, 并对容器中的对象进行了软引用(SoftReference)处理, 从而保证在内存充足的时候池对象不会轻易被jvm垃圾回收, 从而具备很强的缓存能力. 最后两种用Stack作容器. 不带key的对象池是对前面池技术原理的一种简单实现, 带key的相对复杂一些, 它会将池对象按照key来进行分类, 具备相同的key被划分到一组类别中, 所以有多少个key, 就会有多少个容器. 之因此须要带key的这种对象池, 是由于普通的对象池经过makeObject()方法建立的对象基本上都是如出一辙的, 由于无法传递参数来对池对象进行定制. 所以四种池对象的区别主要体如今内部的容器的区别, Stack遵循"后进先出"的原则并能保证线程安全, CursorableLinkedList是一个内部用游标(cursor)来定位当前元素的双向链表, 是非线程安全的, 可是能知足对容器的并发修改.ArrayList是非线程安全的, 便利方便的容器.

使用对象池的通常步骤:建立一个池对象工厂, 将该工厂注入到对象池中, 当要取池对象, 调用borrowObject, 当要归还池对象时, 调用returnObject, 销毁池对象调用clear(), 若是要连池对象工厂也一块儿销毁, 则调用close().
下面是一些时序图: 
borrowObject: 
并发


returnObject: 
jvm


invalidateObject: 
函数

apache的链接池工具库common-dbcp是common-pool在数据库访问方面的一个具体应用.当对common-pool熟悉以后, 对common-dbcp就很好理解了. 它经过对已有的Connection, Statment对象包装成池对象PoolableConnection, PoolablePreparedStatement. 而后在这些池化的对象中, 持有一个对对象池的引用, 在关闭的时候, 不进行真正的关闭处理, 而是经过调用:工具

Java代码   收藏代码
  1. _pool.returnObject(this);  
  2. 或  
  3.  _pool.returnObject(_key,this);  

 

这样一句, 将链接对象放回链接池中. 
而对应的对象池前者采用的是ObjectPool, 后者是KeyedObjectPool, 由于一个数据库只对应一个链接, 而执行操做的Statement却根据Sql的不一样会分不少种. 所以须要根据sql语句的不一样屡次进行缓存
在对链接池的管理上, common-dbcp主要采用两种对象: 
一个是PoolingDriver, 另外一个是PoolingDataSource, 两者的区别是PoolingDriver是一个更底层的操做类, 它持有一个链接池映射列表, 通常针对在一个jvm中要链接多个数据库, 然后者相对简单一些. 内部只能持有一个链接池, 即一个数据源对应一个链接池.
下面是common-dbcp的结构关系: 
性能



下面是参考了common-dbcp的例子以后写的一个从链接池中获取链接的工具类

Java代码   收藏代码
  1. /** 
  2.  * 建立链接 
  3.  *  
  4.  * @since 2009-1-22 下午02:58:35 
  5.  */  
  6. public class ConnectionUtils {  
  7.     // 一些common-dbcp内部定义的protocol  
  8.     private static final String POOL_DRIVER_KEY = "jdbc:apache:commons:dbcp:";  
  9.     private static final String POLLING_DRIVER = "org.apache.commons.dbcp.PoolingDriver";  
  10.   
  11.     /** 
  12.      * 取得池化驱动器 
  13.      *  
  14.      * @return 
  15.      * @throws ClassNotFoundException 
  16.      * @throws SQLException 
  17.      */  
  18.     private static PoolingDriver getPoolDriver() throws ClassNotFoundException,  
  19.             SQLException {  
  20.         Class.forName(POLLING_DRIVER);  
  21.         return (PoolingDriver) DriverManager.getDriver(POOL_DRIVER_KEY);  
  22.     }  
  23.   
  24.     /** 
  25.      * 销毁全部链接 
  26.      *  
  27.      * @throws Exception 
  28.      */  
  29.     public static void destory() throws Exception {  
  30.         PoolingDriver driver = getPoolDriver();  
  31.         String[] names = driver.getPoolNames();  
  32.         for (String name : names) {  
  33.             driver.getConnectionPool(name).close();  
  34.         }  
  35.     }  
  36.   
  37.     /** 
  38.      * 从链接池中获取数据库链接 
  39.      */  
  40.     public static Connection getConnection(TableMetaData table)  
  41.             throws Exception {  
  42.         String key = table.getConnectionKey();  
  43.   
  44.         PoolingDriver driver = getPoolDriver();  
  45.   
  46.         ObjectPool pool = null;  
  47.         // 这里找不到链接池会抛异常, 须要catch一下  
  48.         try {  
  49.             pool = driver.getConnectionPool(key);  
  50.         } catch (Exception e) {  
  51.         }  
  52.           
  53.         if (pool == null) {  
  54.             // 根据数据库类型构建链接工厂  
  55.             ConnectionFactory connectionFactory = null;  
  56.             if (table.getDbAddr() != null  
  57.                     && TableMetaData.DB_TYPE_MYSQL == table.getDbType()) {  
  58.                 Class.forName(TableMetaData.MYSQL_DRIVER);  
  59.                 connectionFactory = new DriverManagerConnectionFactory(table  
  60.                         .getDBUrl(), null);  
  61.             } else {  
  62.                 Class.forName(TableMetaData.ORACLE_DRIVER);  
  63.                 connectionFactory = new DriverManagerConnectionFactory(table  
  64.                         .getDBUrl(), table.getDbuser(), table.getDbpass());  
  65.             }  
  66.               
  67.             // 构造链接池  
  68.             ObjectPool connectionPool = new GenericObjectPool(null);  
  69.             new PoolableConnectionFactory(connectionFactory, connectionPool,  
  70.                     nullnullfalsetrue);  
  71.               
  72.             // 将链接池注册到driver中  
  73.             driver.registerPool(key, connectionPool);  
  74.         }  
  75.   
  76.         // 从链接池中拿一个链接  
  77.         return DriverManager.getConnection(POOL_DRIVER_KEY + key);  
  78.     }  
  79.   
  80. }  

 

虽然对象池技术在实际开发过程当中用的不是不少, 可是理解以后对咱们写程序仍是有莫大的好处的, 至少我是这样的

相关文章
相关标签/搜索