前面讲述了不带key的对象池,本文重点介绍另一种对象池——带key的,这种对象池在实际应用中更加广泛。例如:我们在rpc的系统中,需要对rpc对象进行池化提升其效率,但在实际环境中我们通常考虑ha,会对一个rpc服务在不同服务器上部署多个,这种情况下如果使用普通的对象池就会把所有服务器上部署的rcp服务对象放到一个池子中,不利于负载均衡,使用带有key的对象池可以很好做到负载均衡和池化对象。
一、重点接口介绍:
在Apache-commons-pool-1.6中,对带key的对象池也同样定义了三个顶级接口:KeyedObjectPool<k,v>、KeyedObjectPoolFactory<K, V>、KeyedPoolableObjectFactory<K, V>;和不带key的对象池那三个接口作用一样,其中KeyedObjectPool和KeyedObjectPoolFactory在功能上是一样的(都有三个不同的实现类),不同点仅在于使用上不同(后者通过工厂的方式使用),具体实例见后面;KeyedPoolableObjectFactory是池化对象接口,被池化的对象需要实现该接口。
1)对象池接口:
KeyedObjectPool<k,v>接口用于管理要被池化对象的借出(borrowObject)、归还(returnObject)、失效移除(invalidateObject)、预加载(addObject)以及对象池的清空(clear、close)等,它通过PoolableObjectFactory来完成相应对象的各种操作。eyedObjectPoolFactory<K, V>接口是对KeyedObjectPool<k,v>的一个工厂化封装,用于生产KeyedObjectPool<k,v>接口。2)池化对象接口:
eyedPoolableObjectFactory<K, V>接口用于管理被池化对象(被池化的对象需要实现该接口),主要功能包括对象的产生(makeObject),激活(activateObject),挂起(passivateObject),检验(validateObject)和销毁(destroyObject)等。
二、带key的对象池使用:
1、对象池:
和不带key的对象池一样,他们都统一遵循对象池的内部结构:idle区、abandom区、invalid区;同时也遵循一套对象池内部的驱逐、逐放、有效性探测等策略;在使用上也是先borrowObject,使用完毕后需要returnObject(不同点在于带key的对象池borrowObject的时候需要指定key,returnObject时也要指定key)。
2、池化对象:
和不带key的对象池一样,他们都遵循一套池化对象的状态、池化对象生命周期,以及池化对象的组织结构。
三、实现类:
KeyedObjectPool<k,v>对象池接口下面有两个实现类:GenericKeyedObjectPool、StackKeyedObjectPool
1、GenericKeyedObjectPool:(重点)
GenericKeyedObjectPool同GenericObjectPool一样,采用LIFO/FIF,池的默认行为是一个LIFO,这就意味着,当池中有空闲可用的对象时,调用borrowObject方法会返回最近(“后进”)的实例。如果LIFO策略在池中是false的,实例的返回按相反的顺序,-先进 - 先出。它利用一个org.apache.commons.collections.CursorableLinkedList对象来保存对象池里的对象。
1)这种对象池的特色是:
- 可以设定最多能从池中借出多少个对象。
- 可以设定池中最多能保存多少个对象。
- 可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
- 可以分别设定对象借出和还回时,是否进行有效性检查。
- 可以设定是否使用一个单独的线程,对池内对象进行后台清理。
最简单的是GenericKeyedObjectPool(KeyedPoolableObjectFactory factory),仅仅指明要用的KeyedPoolableObjectFactory实例,其它参数则采用默认值;此外可以通过GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, GenericKeyedObjectPool.Config config) 构造函数来构造复杂的配置,其中GenericKeyedObjectPool.Config可以设置:
- int maxActive
- int maxIdle
- long maxWait
- long minEvictableIdleTimeMillis
- int numTestsPerEvictionRun
- boolean testOnBorrow
- boolean testOnReturn
- boolean testWhileIdle
- long timeBetweenEvictionRunsMillis
- byte whenExhaustedAction
2、StackKeyedObjectPool
同StackObjectPool一样,在这里就不多列举了。
四、实例:
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.BaseKeyedPoolableObjectFactory;
public class MyBeanKeyedPool extends BaseKeyedPoolableObjectFactory<String,MyBean>{
private ThreadLocalRandom random = ThreadLocalRandom.current();
@Override
public void destroyObject(String key,MyBean client) throws Exception {
System.out.println("======================================================destroy...");
}
@Override
public boolean validateObject(String key,MyBean client) {
return true;
}
@Override
public MyBean makeObject(String key) throws Exception {
System.out.println("make...");
long id = random.nextLong(10000000);
return new MyBean(id,System.currentTimeMillis()+"_test",key);
}
}
说明:BaseKeyedPoolableObjectFactory抽象类实现了KeyedPoolableObjectFactory接口。
3)测试1:(使用GenericKeyedObjectPool接口)
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.GenericKeyedObjectPool;
import cn.eud.nuc.pool.bean.MyBean;
import cn.eud.nuc.pool.bean.MyBeanKeyedPool;
public class TestKeyed {
public static void main(String...strings) throws InterruptedException {
MyBeanKeyedPool myBeanPool = new MyBeanKeyedPool();
GenericKeyedObjectPool.Config poolConfig = new GenericKeyedObjectPool.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;
GenericKeyedObjectPool<String,MyBean> genericObjectPool = new GenericKeyedObjectPool<>(myBeanPool, poolConfig);
//预热
try {
genericObjectPool.addObject("0");
genericObjectPool.addObject("1");
} catch (Exception e) {
e.printStackTrace();
}
ExecutorService pool = Executors.newFixedThreadPool(200);
for (int i=0;i<5000;i++) {
pool.submit(new MyThread2(genericObjectPool));
}
//关闭
/**pool.shutdown();
try {
genericObjectPool.close();
} catch (Exception e) {
e.printStackTrace();
}*/
}
}
class MyThread2 implements Runnable {
private ThreadLocalRandom random = ThreadLocalRandom.current();
private GenericKeyedObjectPool<String,MyBean> genericObjectPool;
public MyThread2(GenericKeyedObjectPool<String,MyBean> genericObjectPool) {
super();
this.genericObjectPool = genericObjectPool;
}
@Override
public void run() {
int nextInt = random.nextInt(2);
MyBean borrowObject = null;
boolean flag = true;
String key = ""+nextInt;
try {
borrowObject = genericObjectPool.borrowObject(key);
borrowObject.abc(nextInt);
} catch (Exception e) {
flag = false;
e.printStackTrace();
} finally {
try {
if (flag) {
genericObjectPool.returnObject(key,borrowObject);
} else {
genericObjectPool.invalidateObject(key,borrowObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4)测试2:(使用GenericKeyedObjectPoolFactory接口)
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.KeyedObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import cn.eud.nuc.pool.bean.MyBean;
import cn.eud.nuc.pool.bean.MyBeanKeyedPool;
public class TestKeyed2 {
public static void main(String...strings) throws InterruptedException {
MyBeanKeyedPool myBeanPool = new MyBeanKeyedPool();
GenericKeyedObjectPool.Config poolConfig = new GenericKeyedObjectPool.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;
GenericKeyedObjectPoolFactory<String,MyBean> genericObjectPoolFactory = new GenericKeyedObjectPoolFactory<>(myBeanPool, poolConfig);
KeyedObjectPool<String, MyBean> createPool = genericObjectPoolFactory.createPool();
//预热
try {
createPool.addObject("0");
createPool.addObject("1");
} catch (Exception e) {
e.printStackTrace();
}
ExecutorService pool = Executors.newFixedThreadPool(200);
for (int i=0;i<5000;i++) {
pool.submit(new MyThread3(createPool));
}
//关闭
/*pool.shutdown();
try {
createPool.close();
} catch (Exception e) {
e.printStackTrace();
}*/
}
}
class MyThread3 implements Runnable {
private ThreadLocalRandom random = ThreadLocalRandom.current();
private KeyedObjectPool<String, MyBean> createPool;
public MyThread3(KeyedObjectPool<String, MyBean> createPool) {
super();
this.createPool = createPool;
}
@Override
public void run() {
int nextInt = random.nextInt(2);
MyBean borrowObject = null;
boolean flag = true;
String key = ""+nextInt;
try {
borrowObject = createPool.borrowObject(key);
borrowObject.abc(nextInt);
} catch (Exception e) {
flag = false;
e.printStackTrace();
} finally {
try {
if (flag) {
createPool.returnObject(key,borrowObject);
} else {
createPool.invalidateObject(key,borrowObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
参考:
http://blog.csdn.net/bhy5683/article/details/8776498