对象池(ObjectPool): 掌管对象的生命周期,获取,激活,验证,钝化,销毁等
池对象(PooledObject): 被创建在池中的对象,自己可以有一些附加信息
池对象工厂(PooledObjectFactory): 池中对象各个生命周期的具体实现,怎么创建,怎么验证,怎么销毁。
对象池化主要用于减少对象在创建和销毁上面的开销,如果是小对象则不需要池化,如果是大对象可以考虑池化,对于像数据库连接、网络之类的重对象来说是很有必要池化的,开发者自己根据需求判断,如果创建某种对象成为了影响程序性能的关键因素则需要池化。
1、maven引入:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2、创建池对象工厂,继承BasePooledObjectFactory
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
/**
* JdbcUtils工具类对象池工厂
*/
public class JdbcUtilsPoolFactory extends BasePooledObjectFactory<JdbcUtils> {
static GenericObjectPool<JdbcUtils> pool = null;
// 取得对象池工厂实例
public synchronized static GenericObjectPool<JdbcUtils> getInstance() {
if (pool == null) {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(-1);
poolConfig.setMaxTotal(-1);
poolConfig.setMinIdle(100);
poolConfig.setLifo(false);
pool = new GenericObjectPool<JdbcUtils>(new JdbcUtilsPoolFactory(), poolConfig);
}
return pool;
}
public static JdbcUtils borrowObject() throws Exception{
return (JdbcUtils) JdbcUtilsPoolFactory.getInstance().borrowObject();
}
public static void returnObject(JdbcUtils jdbcUtils) throws Exception{
JdbcUtilsPoolFactory.getInstance().returnObject(jdbcUtils);
}
public static void close() throws Exception{
JdbcUtilsPoolFactory.getInstance().close();
}
public static void clear() throws Exception{
JdbcUtilsPoolFactory.getInstance().clear();
}
@Override
public JdbcUtils create() throws Exception {
return new JdbcUtils();
}
@Override
public PooledObject<JdbcUtils> wrap(JdbcUtils obj) {
return new DefaultPooledObject<JdbcUtils>(obj);
}
}
3、使用对象池
public static void main(String[] args) throws Exception {
JdbcUtils jdbcUtils = JdbcUtilsPoolFactory.borrowObject();
jdbcUtils.domestring();
JdbcUtilsPoolFactory.returnObject(jdbcUtils);
}
1、对象BaseObject
public class BaseObject {
//记录从池中取出次数
private int num;
private boolean active;
public BaseObject(){
active = true;
System.out.println("new BaseObject!!!!!");
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
2、MyPoolableFactory对象池,实现PoolableObjectFactory
import org.apache.commons.pool.PoolableObjectFactory;
public class MyPoolableFactory implements PoolableObjectFactory {
//重新初始化实例返回池
@Override
public void activateObject(Object arg0) throws Exception {
((BaseObject)arg0).setActive(true);
}
//销毁被破坏的实例
@Override
public void destroyObject(Object arg0) throws Exception {
arg0 = null;
}
//创建一个实例到对象池
@Override
public Object makeObject() throws Exception {
BaseObject bo = new BaseObject();
return bo;
}
//取消初始化实例返回到空闲对象池
@Override
public void passivateObject(Object arg0) throws Exception {
((BaseObject)arg0).setActive(false);
}
//验证该实例是否安全
@Override
public boolean validateObject(Object arg0) {
if(((BaseObject)arg0).isActive())
return true;
else
return false;
}
}
3、测试PoolableObjectFactory
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
/*
* 这里的池声明用ObjectPool或者GenericObjectPool的区别在于:
* (1)ObjectPool :
GenericObjectPool这种对象池的特色是:
可以设定最多能从池中借出多少个对象。
可以设定池中最多能保存多少个对象。
可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
可以分别设定对象借出和还回时,是否进行有效性检查。
可以设定是否使用一个单独的线程,对池内对象进行后台清理。
……
StackObjectPool:使用LIFO行为实现的ObjectPool。
SoftReferenceObjectPool:
使用LIFO行为实现的ObjectPool。此外,在这个对象池实现中,每个对象都会被包装到一个SoftReference中。
SoftReference允许垃圾回收机制在需要释放内存时回收对象池中的对象。
源码GenericObjectPool.java类内部的setConfig方法
1. 参数maxActive指明能从池中借出的对象的最大数目。如果这个值不是正数,表示没有限制。
2. 参数whenExhaustedA ction指定在池中借出对象的数目已达极限的情况下,调用它的borrowObject方法时的行为。可以选用的值有:
GenericObjectPool.WHEN_EXHAUSTED_BLOCK,表示等待;
GenericObjectPool.WHEN_EXHAUSTED_GROW,表示创建新的实例(不过这就使maxActive参数失去了意义);
GenericObjectPool.WHEN_EXHAUSTED_FAIL,表示抛出一个java.util.NoSuchElementException异常。
3. 参数maxWait指明若在对象池空时调用borrowObject方法的行为被设定成等待,最多等待多少毫秒。如果等待时间超过了这个数值,则会抛出一个java.util.NoSuchElementException异常。如果这个值不是正数,表示无限期等待。
4. 参数testOnBorrow设定在借出对象时是否进行有效性检查。
5. 参数testOnBorrow设定在还回对象时是否进行有效性检查。
6. 参数timeBetweenEvictionRunsMillis,设定间隔每过多少毫秒进行一次后台对象清理的行动。如果这个值不是正数,则实际上不会进行后台对象清理。
7. 参数minEvictableIdleTimeMillis,设定在进行后台对象清理时,视休眠时间超过了多少毫秒的对象为过期。过期的对象将被回收。如果这个值不是正数,那么对休眠时间没有特别的约束。
8. 参数testWhileIdle,则设定在进行后台对象清理时,是否还对没有过期的池内对象进行有效性检查。不能通过有效性检查的对象也将被回收。
9. 参数lifo,池对象的放入和取出默认是后进先出的原则,默认是true,代表后进先出,设置为false代表先进先出。
*/
public class PoolTest {
public static void main(String[] args) {
BaseObject bo = null;
PoolableObjectFactory factory = new MyPoolableFactory();
GenericObjectPool pool = new GenericObjectPool(factory);
//这里两种池都可以,区别下文会提到
//ObjectPool pool = new StackObjectPool(factory);
try {
for(int i = 0; i < 5; i++) {
System.out.println("\n==========="+i+"===========");
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+pool.getNumIdle());
//从池里取一个对象,新创建makeObject或将以前闲置的对象取出来
bo = (BaseObject)pool.borrowObject();
System.out.println("bo:"+bo);
System.out.println("池中所有在用实例数量pool.getNumActive():"+pool.getNumActive());
if((i%2) == 0) {
//用完之后归还对象
pool.returnObject(bo);
System.out.println("归还对象!!!!");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(bo != null) {
pool.returnObject(bo);
}
//关闭池
pool.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1、创建对象BaseObject, 代码同上
2、创建MyKeyPoolableFactory, 实现KeyedPoolableObjectFactory
import org.apache.commons.pool.KeyedPoolableObjectFactory;
public class MyKeyPoolableFactory implements KeyedPoolableObjectFactory {
//重新初始化实例返回池
@Override
public void activateObject(Object arg0, Object arg1) throws Exception {
((BaseObject)arg1).setActive(true);
}
//销毁被破坏的实例
@Override
public void destroyObject(Object arg0, Object arg1) throws Exception {
arg1 = null;
}
//创建一个实例到对象池
@Override
public Object makeObject(Object arg0) throws Exception {
//这里从数据库里查询出使用次数最少的配置
BaseObject bo = new BaseObject();
bo.setNum(0);
return bo;
}
//取消初始化实例返回到空闲对象池
@Override
public void passivateObject(Object arg0, Object arg1) throws Exception {
((BaseObject)arg1).setActive(false);
}
//验证该实例是否安全 true:正在使用
@Override
public boolean validateObject(Object arg0, Object arg1) {
//这里可以判断实例状态是否可用
if(((BaseObject)arg1).isActive())
return true;
else
return false;
}
}
3、测试MyKeyPoolableFactory
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
public class KeyPoolTest {
public static void main(String[] args) {
BaseObject bo = null;
BaseObject bo1 = null;
BaseObject bo2 = null;
KeyedPoolableObjectFactory keyFactory = new MyKeyPoolableFactory();
GenericKeyedObjectPool keyPool = new GenericKeyedObjectPool(keyFactory);
//keyPool.setLifo(false);
try {
//这里添加池对象,只需要传入key就会默认调用makeObject()方法创建一个对象
keyPool.addObject("一级");
keyPool.addObject("二级");
//这里注释掉,不初始创建这个键的池对象
//keyPool.addObject("三级");
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+keyPool.getNumIdle());
for (int i = 0; i < 5; i++) {
//从池里取对象
bo = (BaseObject) keyPool.borrowObject("一级");
bo.setNum(bo.getNum()+1);
System.out.println("一级"+i+"-------"+bo+"-------"+bo.getNum());
bo1 = (BaseObject) keyPool.borrowObject("二级");
bo1.setNum(bo1.getNum()+1);
System.out.println("二级"+i+"-------"+bo1+"-------"+bo1.getNum());
//上边注释掉的那行代码,这里取对象的时候如果没有闲置对象,也会默认去创建一个key="三级"的池对象
bo2 = (BaseObject) keyPool.borrowObject("三级");
bo2.setNum(bo2.getNum()+1);
System.out.println("三级"+i+"-------"+bo2+"-------"+bo2.getNum());
if(i<3) {
//用完之后归还对象
keyPool.returnObject("一级", bo);
keyPool.returnObject("二级", bo1);
keyPool.returnObject("三级", bo2);
System.out.println("归还对象!!!");
}
}
//当前池里的实例数量
System.out.println("池中所有在用实例pool.getNumActive():"+keyPool.getNumActive());
//当前池里的处于闲置状态的实例
System.out.println("池中处于闲置状态的实例pool.getNumIdle():"+keyPool.getNumIdle());
} catch (Exception e) {
e.printStackTrace();
}
//这里就不写finally了,偷懒了,这里应该关闭池的
}
}