一、重点接口介绍:
在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;
- 如果池中有idle的对象(idle>0),直接返回该对象,并将idle-1;
- 如果池中没有idle的对象,调用池化对象接口实现类中的makeObject方法创建对象;如果目前对象池的active数达到maxactive,那么阻塞等待;
- 如果配置了testonborrow=ture,那么在获取对象之前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;
2)使用完对象必须要归还给对象池,通过对象池(ObjectPool/ObjectPoolFactory)接口的实现类中的returnObject方法将对象归还到对象池中,并将active标记-1;
- 如果配置了testonreturn=ture,那么在归还对象前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;
- 如果idle数大于maxidle,则销毁对象,否则唤醒上面阻塞的进程或者放到idle区(idle+1);
- 如果配置了removeAbandonedTimeout,则超过该事件的池化对象直接进入放逐区;
注:对象池只有在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)这种对象池的特色是:
- 可以为对象池指定一个初始的参考大小(当空间不够时会自动增长)。
- 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
- 可以为对象池指定一个可保存的对象数目的上限。达到这个上限之后,再向池里送回的对象会被自动送去回收。
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)这种对象池的特色是:
- 可以保存任意多个对象,不会有容量已满的情况发生。
- 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
- 可以在初始化同时,在池内预先创建一定量的对象。
- 当内存不足的时候,池中的对象可以被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;
}
@Override
public 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();
@Override
public MyBean makeObject() throws Exception {
System.out.println("make...");
long id = random.nextLong(10000000);
return new MyBean(id,System.currentTimeMillis()+"_test","");
}
@Override
public void destroyObject(MyBean client) throws Exception {
System.out.println("======================================================destroy...");
}
@Override
public 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;
}
@Override
public 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();
}
}
}
}
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;
}
@Override
public 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