java对象池commons-pool-1.6详解(二)

来源:互联网 发布:vb net从入门到精通 编辑:程序博客网 时间:2024/05/23 14:42
上篇文章 我们详细介绍了commons-pool-1.6 java对象池的原理和基本概念,本文详细介绍不带key的对象池(ObjectPool)具体使用。

一、重点接口介绍

在Apache-commons-pool-1.6中,对不带key的对象池定义了三个顶级接口:ObjectPool、ObjectPoolFactory、PoolableObjectFactory;其中ObjectPool和ObjectPoolFactory在功能上是一样的(都有三个不同的实现类),不同点仅在于使用上不同(后者通过工厂的方式使用),具体实例见后面。PoolableObjectFactory是池化对象接口,被池化的对象需要实现该接口。

1)对象池接口:

ObjectPool接口用于管理要被池化对象的借出(borrowObject)、归还(returnObject)、失效移除(invalidateObject)、预加载(addObject)以及对象池的清空(clear、close)等,它通过PoolableObjectFactory来完成相应对象的各种操作。ObjectPoolFactory接口是对ObjectPool接口的工厂化封装,用于生产ObjectPool接口。

2)池化对象接口:

PoolableObjectFactory用于管理被池化对象(被池化的对象需要实现该接口),主要功能包括对象的产生(makeObject),激活(activateObject),挂起(passivateObject),检验(validateObject)和销毁(destroyObject)

二、对象池使用流程

1)使用者通过对象池(ObjectPool/ObjectPoolFactory)接口实现类中的borrowObject方法来从对象池中获取对象,并将active标记+1;

  1. 如果池中有idle的对象(idle>0),直接返回该对象,并将idle-1;
  2. 如果池中没有idle的对象,调用池化对象接口实现类中的makeObject方法创建对象;如果目前对象池的active数达到maxactive,那么阻塞等待;
  3. 如果配置了testonborrow=ture,那么在获取对象之前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;

2)使用完对象必须要归还给对象池,通过对象池(ObjectPool/ObjectPoolFactory)接口的实现类中的returnObject方法将对象归还到对象池中,并将active标记-1;

  1. 如果配置了testonreturn=ture,那么在归还对象前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;
  2. 如果idle数大于maxidle,则销毁对象,否则唤醒上面阻塞的进程或者放到idle区(idle+1);
  3. 如果配置了removeAbandonedTimeout,则超过该事件的池化对象直接进入放逐区;
3)驱逐检验:如果配置了timeBetweenEvictionRunsMillis,为了保证对象池的伸缩性(避免浪费资源)对象池会对idle状态的池化对象进行驱逐(minEvictableIdleTimeMillis控制驱逐空闲时间);

:对象池只有在borrowObject的时候才回去真正创建对象(调用makeObject或者从池中的idle队列中获取),如果要预申请对象,需要调用吃对象接口ObjectPool的addObject方法。



三、对象池实现类

ObjectPool接口下面有三个实现类:GenericObjectPool、StackObjectPool、SoftReferenceObjectPool。

1、genericObjectpool:(重点)

GenericObjectPool采用LIFO/FIF,池的默认行为是一个LIFO,这就意味着,当池中有空闲可用的对象时,调用borrowObject方法会返回最近(“后进”)的实例。如果LIFO策略在池中是false的,实例的返回按相反的顺序,-先进 - 先出。它利用一个org.apache.commons.collections.CursorableLinkedList对象来保存对象池里的对象。

1)这种对象池的特色是:

  • 可以设定最多能从池中借出多少个对象。
  • 可以设定池中最多能保存多少个对象。
  • 可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
  • 可以分别设定对象借出和还回时,是否进行有效性检查。
  • 可以设定是否使用一个单独的线程,对池内对象进行后台清理。

2)构造函数:

GenericObjectPool一共7个构造函数,最简单的是GenericObjectPool(PoolableObjectFactory factory),仅仅指明要用的PoolableObjectFactory实例,其它参数则采用默认值;此外可以通过GenericObjectPool(PoolableObjectFactory factory, GenericObjectPool.Config config) 构造函数来构造复杂的配置,其中GenericObjectPool.Config可以设置:

  • int maxActive
  • int maxIdle
  • long maxWait
  • long minEvictableIdleTimeMillis
  • int numTestsPerEvictionRun
  • boolean testOnBorrow
  • boolean testOnReturn
  • boolean testWhileIdle
  • long timeBetweenEvictionRunsMillis
  • byte whenExhaustedAction

2、StackObjectPool: 

StackObjectPool采用LIFO,利用一个java.util.Stack对象来保存对象池里的对象。

1)这种对象池的特色是:

  1. 可以为对象池指定一个初始的参考大小(当空间不够时会自动增长)。
  2. 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  3. 可以为对象池指定一个可保存的对象数目的上限。达到这个上限之后,再向池里送回的对象会被自动送去回收。

2)构造函数:

StackObjectPool一共6个构造函数,最简单的一个是StackObjectPool(),一切采用默认的设置,也不指明要用的PoolableObjectFactory实例;最复杂的一个则是StackObjectPool(PoolableObjectFactory factory, int max, int init),其中参数factory指明要与之配合使用的PoolableObjectFactory实例、参数max设定可保存对象数目的上限、参数init则指明初始的参考大小。

3、SoftReferenceObjectPool: 

SoftReferenceObjectPool采用LIFO,这种池额外功能是包装了每一个引用对象,允许GC根据内存需求清除这些对象。利用一个java.util.ArrayList对象来保存对象池里的对象。不过它并不在对象池里直接保存对象本身,而是保存它们的“软引用”(Soft Reference)。

1)这种对象池的特色是:

  1. 可以保存任意多个对象,不会有容量已满的情况发生。
  2. 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  3. 可以在初始化同时,在池内预先创建一定量的对象。
  4. 当内存不足的时候,池中的对象可以被Java虚拟机回收。

2)构造方法:

SoftReferenceObjectPool有3个构造方法,最简单的是SoftReferenceObjectPool(),不预先在池内创建对象,也不指明要用的PoolableObjectFactory实例;最复杂的一个则是SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize)。其中:参数factory指明要与之配合使用的PoolableObjectFactory实例、参数initSize则指明初始化时在池中创建多少个对象


四、实例:

1)定义一个被池化的对象:

package cn.eud.nuc.pool.bean;public class MyBean {private Long id;private String name;private String other;public void abc(int inxtInt) throws InterruptedException {Thread.sleep(1000);System.out.println(this.toString());}public MyBean(Long id, String name, String other) {super();this.id = id;this.name = name;this.other = other;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getOther() {return other;}public void setOther(String other) {this.other = other;}@Overridepublic String toString() {return "MyBean [id=" + id + ", name=" + name + ", other=" + other + "]";}}
2)实现池化接口:

package cn.eud.nuc.pool.bean;import java.util.concurrent.ThreadLocalRandom;import org.apache.commons.pool.BasePoolableObjectFactory;public class MyBeanPool extends BasePoolableObjectFactory<MyBean>{private ThreadLocalRandom random = ThreadLocalRandom.current();@Overridepublic MyBean makeObject() throws Exception {System.out.println("make...");long id = random.nextLong(10000000);return new MyBean(id,System.currentTimeMillis()+"_test","");}@Overridepublic void destroyObject(MyBean client) throws Exception {System.out.println("======================================================destroy...");}@Overridepublic boolean validateObject(MyBean client) {return true;}}
3)测试类1:(使用GenericObjectPool接口)

package cn.eud.nuc.pool;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ThreadLocalRandom;import org.apache.commons.pool.impl.GenericObjectPool;import cn.eud.nuc.pool.bean.MyBean;import cn.eud.nuc.pool.bean.MyBeanPool;public class Test {public static void main(String...strings) throws Exception {MyBeanPool myBeanPool = new MyBeanPool();GenericObjectPool.Config poolConfig = new GenericObjectPool.Config();poolConfig.maxActive = 100;poolConfig.maxIdle = 1;//poolConfig.minIdle = 0;poolConfig.minEvictableIdleTimeMillis = 1000000000;poolConfig.timeBetweenEvictionRunsMillis = 10 * 2L;poolConfig.testOnBorrow=false;poolConfig.testOnReturn=true;poolConfig.testWhileIdle=true;poolConfig.lifo = false;//poolConfig.maxWait = 100000000;GenericObjectPool<MyBean> genericObjectPool = new GenericObjectPool<MyBean>(myBeanPool, poolConfig);genericObjectPool.addObject();genericObjectPool.addObject();genericObjectPool.addObject();genericObjectPool.addObject();ExecutorService pool = Executors.newFixedThreadPool(200);for (int i=0;i<5000;i++) {pool.submit(new MyThread(genericObjectPool));}}}class MyThread implements Runnable {private ThreadLocalRandom random = ThreadLocalRandom.current();private GenericObjectPool<MyBean> genericObjectPool;public MyThread(GenericObjectPool<MyBean> genericObjectPool) {super();this.genericObjectPool = genericObjectPool;}@Overridepublic void run() {int nextInt = random.nextInt(100);MyBean borrowObject = null;boolean flag = true;try {borrowObject = genericObjectPool.borrowObject();borrowObject.abc(nextInt);} catch (Exception e) {flag = false;e.printStackTrace();} finally {try {if (flag) {genericObjectPool.returnObject(borrowObject);} else {genericObjectPool.invalidateObject(borrowObject);}} catch (Exception e) {e.printStackTrace();}}}}


4)测试类2(使用GenericObjectPoolFactory接口)

package cn.eud.nuc.pool;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ThreadLocalRandom;import org.apache.commons.pool.ObjectPool;import org.apache.commons.pool.impl.GenericObjectPool;import org.apache.commons.pool.impl.GenericObjectPoolFactory;import cn.eud.nuc.pool.bean.MyBean;import cn.eud.nuc.pool.bean.MyBeanPool;public class Test2 {public static void main(String...strings) throws InterruptedException {MyBeanPool myBeanPool = new MyBeanPool();GenericObjectPool.Config poolConfig = new GenericObjectPool.Config();poolConfig.maxActive = 100;poolConfig.maxIdle = 1;//poolConfig.minIdle = 0;poolConfig.minEvictableIdleTimeMillis = 1000000000;poolConfig.timeBetweenEvictionRunsMillis = 10 * 2L;poolConfig.testOnBorrow=false;poolConfig.testOnReturn=true;poolConfig.testWhileIdle=true;poolConfig.lifo = false;//poolConfig.maxWait = 100000000;GenericObjectPoolFactory<MyBean> genericObjectPoolFactory = new GenericObjectPoolFactory<>(myBeanPool, poolConfig);ObjectPool<MyBean> createPool = genericObjectPoolFactory.createPool();ExecutorService pool = Executors.newFixedThreadPool(200);for (int i=0;i<5000;i++) {pool.submit(new MyThread1(createPool));}}}class MyThread1 implements Runnable {private ThreadLocalRandom random = ThreadLocalRandom.current();private ObjectPool<MyBean> genericObjectPool;public MyThread1(ObjectPool<MyBean> genericObjectPool) {super();this.genericObjectPool = genericObjectPool;}@Overridepublic void run() {int nextInt = random.nextInt(100);MyBean borrowObject = null;boolean flag = true;try {borrowObject = genericObjectPool.borrowObject();borrowObject.abc(nextInt);} catch (Exception e) {flag = false;e.printStackTrace();} finally {try {if (flag) {genericObjectPool.returnObject(borrowObject);} else {genericObjectPool.invalidateObject(borrowObject);}} catch (Exception e) {e.printStackTrace();}}}}

参考:

https://www.cnblogs.com/shipengzhi/archive/2011/06/02/2068565.html

原创粉丝点击