您的位置:首页 > 运维架构 > Apache

Java模块 -- Apache Commons Pool 对象池_简介

2017-05-21 08:52 375 查看
Apache Commons Pool 对象池

1. 对象池
a. 对象池就是以"空间换时间"的一种常用缓存机制,这里的"时间"特指创建时间。
b. 如果一种对象的创建过程非常耗时的话,那么请使用对象池。
c. 从内部原理简单的说,对象池技术就是将创建的对象放到一个容器中,用完之后不是销毁而是再放回该容器,让其他的对象调用。
d. 对象池中还涉及到一些高级的技术,比如过期销毁,被破坏时销毁,对象数超过池大小销毁,对象池中没有可用空闲对象时等待等等。

2. 为什么使用Commons pool 对象池技术?
a. 创建新的对象并初始化,可能会消耗很多时间。
b.在需要大量或者频繁生成这样的对象的时候,就可能会对性能造成一些不可忽略的影响。

3. 对象池技术解释
a.对象池的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销.
b. 用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。
c. 并非所有对象都适合拿来池化――因为维护对象池也要造成一定开销。
  对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。
  但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。

综上所述 :恰当地使用对象池化技术,可以有效地减少对象生成和初始化时的消耗,提高系统的运行效率。

详解:

a. PoolableObjectFactory : 用于管理被池化的对象的产生、激活、挂起、校验和销毁;
i. 创建 PoolableObjectFactory  
1) Pool组件利用PoolableObjectFactory来照看被池化的对象。

2) ObjectPool的实例在需要处理被池化的对象的产生、激活、挂起、校验和销毁工作时,
  就会调用跟它关联在一起的PoolableObjectFactory实例的相应方法来操作。

3) PoolableObjectFactory是在org.apache.commons.pool包中定义的一个接口。
  实际使用的时候需要利用这个接口的一个具体实现。
  Pool组件本身没有包含任何一种PoolableObjectFactory实现,需要根据情况自行创立。

b. ObjectPool
i. 用于管理要被池化的对象的借出和归还,并通知PoolableObjectFactory完成相应的工作;

c. ObjectPoolFactory
i. 用于大量生成相同类型和设置的ObjectPool。 

工厂类

import org.apache.commons.pool.PoolableObjectFactory;

//1.创建一个实现了PoolableObjectFactory接口的类。
/**
* PoolableObjectFactory接口 : 池对象工厂
* 		用来创建池对象,将不用的池对象进行钝化(passivateObject),
* 		对要使用的池对象进行激活(activeObject),
* 		对池对象进行验证(validateObject),
* 		对有问题的池对象进行销毁(destroyObject)等工作。
*/

public class PoolableObjectFactorySample implements PoolableObjectFactory {

private static int counter = 0;

@Override
//用于在必要时产生新的对象。
public Object makeObject() throws Exception {
Object obj = String.valueOf(counter++);
System.out.println("Making Object " + obj);
return obj;
}

@Override
//用于将对象“激活”――设置为适合开始使用的状态。
public void activateObject(Object obj) throws Exception {
System.out.println("Activating Object : " + obj);
}

@Override
//用于将对象“挂起”――设置为适合开始休眠的状态。
public void passivateObject(Object obj) throws Exception {
System.err.println("Passivating Object " + obj);

}

@Override
//用于校验一个具体的对象是否仍然有效,已失效的对象会被自动交给destroyObject方法销毁
public boolean validateObject(Object obj) {
//以1/2的概率将对象判定为失效
boolean result = (Math.random() > 0.5);
System.err.println("Validating Object " + obj + " : " + result);
return result;
}

@Override
//用于销毁被validateObject判定为已失效的对象。
public void destroyObject(Object obj) throws Exception {
System.err.println("Destroying Object " + obj);
}

}


测试调用类

import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool.Config;

/**
* @author CYX
*
* GenericObjectPool : 租车公司
* 		作为租车公司,需要提供以下几个服务:
* 			1.租车
* 			2.收回
* 			3.买新车
* 			4.销毁
* 			5.定期检查
*
* PooledObject : 租车公司的所有车辆
*		1.空闲可用的车辆
*		2.已借出的车辆
*		3.认为已丢弃的车辆
*
* BorrowObject : 租车
* 		1.世界那么大,一位年轻人想租辆车出去逛逛
* 		2.老板,先看看有没有空闲的车
* 		3.如果有,则将最近归还的车借出去,并标记为已借出(Active)
* 		     如果没有空闲的车了,就买辆,同时也标记为已借出(这是一家不差钱的公司)
* 		4.老板把标记好的车租给年轻人
*
* ReturnObject : 还车
* 		1.世界那么大,年轻人终于逛完了,回来还车
* 		2.老板把车放回停车场,并把标记改为空闲状态(Idle),可以再被其他人租用。
*
* 这 家公司不仅不差钱,它对车辆的安全还很负责,对于租出去的车,不管是从空闲车辆里取出的,还是新买回的,都会先检查一遍这车的好坏,
* 总不能坑了年轻人,如 果发现有问题,立马再换一辆。归还的时候,也会检查一遍,如果有问题,就扔掉(真土豪).
* 除此之外,公司还专门请了一位车辆安检员,定期对闲置了一段时间 的车辆进行安全检测(Evict Thread),一有问题也扔掉。
*
*
* 有借有还,看上去一切都很美好。
* 	然而现实里总有意外发生:年轻人借走车后,发现世界越逛越大,久久不愿回家。
* 	安检员定期检查时发现这车子都借出去大半年了,还没还回来,是不是丢了?
*  于是掏出手机,”啪“的按了一下,远程将车子熄了火,标记为报废车辆(Abandoned),当作报废处理了。
*
*
*
* Evict Thread(定期检查的安检人员)
* 1.对于已归还标记为空闲的车辆,安检员定期对它们抽查,如果超过一段时间没有使用,看看是否坏掉,坏了就及时作废掉(C2).
* 2.对于标记为已借出的对象,安检员定期检查时发现借出很久都未还,直接作废(D2)。
*
*/
public class ObjectPool {
@SuppressWarnings("unchecked")
public static void main(String[] args) {

Object obj = null;

// 生成一个要用的PoolableObjectFactory类的实例。
PoolableObjectFactorySample factory = new PoolableObjectFactorySample();

Config conf = new Config();
conf.maxActive=10;
conf.whenExhaustedAction=1;

GenericObjectPool pool = new GenericObjectPool(factory,conf);

try {
for (int i = 0; i < 10; i++) {
System.out.println("== " + i + " ==");
obj = pool.borrowObject(); // 需要从对象池中取出对象时,调用该对象池的Object borrowObject()方法。
System.out.println(obj);
pool.returnObject(obj); // 需要将对象放回对象池中时,调用该对象池的void returnObject(Object obj)方法。
}
obj = null; // 明确的设为null,作为对象已归还的标志.
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (obj != null) { // 避免一个对象二次归还
pool.returnObject(obj);
}
pool.close(); //当不再需要使用一个对象池时,调用该对象池的void close()方法,释放它所占据的资源。
} catch (Exception e) {
e.printStackTrace();
}
}
}
}


对象池的配置

maxActive: 链接池中最大连接数,默认为8.
maxIdle: 链接池中最大空闲的连接数,默认为8.
minIdle: 连接池中最少空闲的连接数,默认为0.
maxWait: 当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位,毫秒数;默认为-1.表示永不超时.
minEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除。
softMinEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲链接将会被移除,且保留“minIdle”个空闲连接数。默认为-1.
numTestsPerEvictionRun: 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.
testOnBorrow: 向调用者输出“链接”资源时,是否检测是有有效,如果无效则从连接池中移除,并尝试获取继续获取。默认为false。建议保持默认值.
testOnReturn:  向连接池“归还”链接时,是否检测“链接”对象的有效性。默认为false。建议保持默认值.
testWhileIdle:  向调用者输出“链接”对象时,是否检测它的空闲超时;默认为false。如果“链接”空闲超时,将会被移除。建议保持默认值.
timeBetweenEvictionRunsMillis:  “空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
whenExhaustedAction: 当“连接池”中active数量达到阀值时,即“链接”资源耗尽时,连接池需要采取的手段, 默认为1:
-> 0 : 抛出异常,
-> 1 : 阻塞,直到有可用链接资源
-> 2 : 强制创建新的链接资源
这些属性均可以在org.apache.commons.pool.impl.GenericObjectPool.Config中进行设定。

#设置后进先出的池策略 
lifo=true 
#允许最大活动对象数 
maxActive=24 
#允许最大空闲对象数 
maxIdle=6 
#允许最大等待时间毫秒数 
maxWait=150000 
#被空闲对象回收器回收前在池中保持空闲状态的最小时间毫秒数 
minEvictableIdleTimeMillis=100000 
#允许最小空闲对象数 
minIdle=0 
#设定在进行后台对象清理时,每次检查对象数 
numTestsPerEvictionRun=1 
#指明是否在从池中取出对象前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个. 
testOnBorrow =false 
#指明是否在归还到池中前进行检验 
testOnReturn =false 
#指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除. 
testWhileIdle=false 
#在空闲连接回收器线程运行期间休眠的时间毫秒数. 如果设置为非正数,则不运行空闲连接回收器线程 
timeBetweenEvictionRunsMillis=120000 
#当池中对象用完时,请求新的对象所要执行的动作 
whenExhaustedAction=1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐