java 对象池技术

java 对象池技术

中断了一段时间,再次开始技术之旅;心里有个小目标,先把对象池技术梳理清楚。

1、为什么用对象池

在 java 中,对象的生命周期包括对象创建、对象使用,对象消失三个时间段,其中对象的使用是对象真正需要存活的时间,不好修改,该用的时候还得使用啊。对象的创建和消失就得好好控制下了。对象的创建是比较费时间的,也许感觉不到,好比一个赋值操作int i=1,也是需要耗时的,在比如构造一个对象,一个数组就更加消耗时间。再说对象的消除,在 java 里面使用 GC 来进行对象回收,其实也是需要对对象监控每一个运行状态,包括引用,赋值等。在 Full GC 的时候,会暂停其他操作,独占 CPU。所以,我们需要控制对象的创建数量,也不要轻易的让对象消失,让他的复用更加充分。

2、对象池

对象池其实就是一个集合,里面包含了我们需要的对象集合,当然这些对象都被池化了,也就是被对象池所管理,想要这样的对象,从池子里取个就行,但是用完得归还。对象池的对象最好是创建比较费时的大对象,如果是太简单的对象,再进入池化的时间比自己构建还多,就不划算了。可以理解对象池为单例模式的延展,多例模式,就那么几个对象实例,再多没有了。

3、自定义一个低质量的对象池

首先构造一个池化对象,也就是对实际对象封装下,为什么呢?当然是为了让对象池更好的管理

public class PooledObject {

private T objection = null;// 外界使用的对象

private boolean busy = false; // 此对象是否正在使用的标志,默认没有正在使用

// 构造函数,池化对象

public PooledObject(T objection) {

this.objection = objection;

}

// 返回此对象中的对象

public T getObject() {

return objection;

}

// 设置此对象的,对象

public void setObject(T objection) {

this.objection = objection;

}

// 获得对象对象是否忙

public boolean isBusy() {

return busy;

}

// 设置对象的对象正在忙

public void setBusy(boolean busy) {

this.busy = busy;

}

}

池化对象现在包括两个属性,一个是原始对象的引用,另外一个表示当前对象是否在使用

接下来把对象池写出来

import java.util.Enumeration;

import java.util.Vector;

public abstract class ObjectPool {

public static int numObjects = 10; // 对象池的大小

public static int maxObjects = 50; // 对象池最大的大小

protected Vector> objects = null; // 存放对象池中对象的向量(PooledObject类型)

public ObjectPool() {

}

/*** 创建一个对象池 ***/

public synchronized void createPool() {

// 确保对象池没有创建。如果创建了,保存对象的向量 objects 不会为空

if (objects != null) {

return; // 如果己经创建,则返回

}

// 创建保存对象的向量 , 初始时有 0 个元素

objects = new Vector>();

for (int i = 0; i < numObjects; i++) {

objects.addElement(create());

}

}

public abstract PooledObject create();

public synchronized T getObject() {

// 确保对象池己被创建

if (objects == null) {

return null; // 对象池还没创建,则返回 null

}

T t = getFreeObject(); // 获得一个可用的对象

// 如果目前没有可以使用的对象,即所有的对象都在使用中

while (t == null) {

wait(250);

t = getFreeObject(); // 重新再试,直到获得可用的对象,如果

// getFreeObject() 返回的为 null,则表明创建一批对象后也不可获得可用对象

}

return t;// 返回获得的可用的对象

}

/**

* 本函数从对象池对象 objects 中返回一个可用的的对象,如果 当前没有可用的对象,则创建几个对象,并放入对象池中。

* 如果创建后,所有的对象都在使用中,则返回 null

*/

private T getFreeObject() {

// 从对象池中获得一个可用的对象

T obj = findFreeObject();

if (obj == null) {

createObjects(10); // 如果目前对象池中没有可用的对象,创建一些对象

// 重新从池中查找是否有可用对象

obj = findFreeObject();

// 如果创建对象后仍获得不到可用的对象,则返回 null

if (obj == null) {

return null;

}

}

return obj;

}

public void createObjects(int increment){

for (int i = 0; i < increment; i++) {

if (objects.size() > maxObjects) {

return;

}

objects.addElement(create());

}

}

/**

* 查找对象池中所有的对象,查找一个可用的对象, 如果没有可用的对象,返回 null

*/

private T findFreeObject() {

T obj = null;

PooledObject pObj = null;

// 获得对象池向量中所有的对象

Enumeration> enumerate = objects.elements();

// 遍历所有的对象,看是否有可用的对象

while (enumerate.hasMoreElements()) {

pObj = (PooledObject) enumerate.nextElement();

// 如果此对象不忙,则获得它的对象并把它设为忙

if (!pObj.isBusy()) {

obj = pObj.getObject();

pObj.setBusy(true);

}

}

return obj;// 返回找到到的可用对象

}

/**

* 此函数返回一个对象到对象池中,并把此对象置为空闲。 所有使用对象池获得的对象均应在不使用此对象时返回它。

*/

public void returnObject(T obj) {

// 确保对象池存在,如果对象没有创建(不存在),直接返回

if (objects == null) {

return;

}

PooledObject pObj = null;

Enumeration> enumerate = objects.elements();

// 遍历对象池中的所有对象,找到这个要返回的对象对象

while (enumerate.hasMoreElements()) {

pObj = (PooledObject) enumerate.nextElement();

// 先找到对象池中的要返回的对象对象

if (obj == pObj.getObject()) {

// 找到了 , 设置此对象为空闲状态

pObj.setBusy(false);

break;

}

}

}

/**

* 关闭对象池中所有的对象,并清空对象池。

*/

public synchronized void closeObjectPool() {

// 确保对象池存在,如果不存在,返回

if (objects == null) {

return;

}

PooledObject pObj = null;

Enumeration> enumerate = objects.elements();

while (enumerate.hasMoreElements()) {

pObj = (PooledObject) enumerate.nextElement();

// 如果忙,等 0.5 秒

if (pObj.isBusy()) {

wait(500); // 等

}

// 从对象池向量中删除它

objects.removeElement(pObj);

}

// 置对象池为空

objects = null;

}

/**

* 使程序等待给定的毫秒数

*/

private void wait(int mSeconds) {

try {

Thread.sleep(mSeconds);

} catch (InterruptedException e) {

}

}

}

为了泛化处理,这个对象池是个抽象类,接下来具体实现一个

public class DefaultObjectPool extends ObjectPool {

@Override

public PooledObject create(){

return new PooledObject(new String(""+1));

}

}

最后测试下:

public static void main(String[] args) {

ObjectPool objPool = new DefaultObjectPool();

objPool.createPool();

String obj = objPool.getObject();

objPool.returnObject(obj);

objPool.closeObjectPool();

}

4、开源的对象池

上面的例子基本够用,但是commons-pool提供了一套很好用的对象池组件,使用也很简单。

org.apache.commons.pool.ObjectPool定义了一个简单的池化接口,有三个对应实现,与我们的 Vector 这个集合不同的是,commons-pool提供了多样的集合,包括先进先出(FIFO),后进先出(LIFO)

StackObjectPool :实现了后进先出(LIFO)行为。

SoftReferenceObjectPool: 实现了后进先出(LIFO)行为。另外,对象池还在SoftReference 中保存了每个对象引用,允许垃圾收集器针对内存需要回收对象。

KeyedObjectPool定义了一个以任意的key访问对象的接口(可以池化对种对象),有两种对应实现。

GenericKeyedObjectPool :实现了先进先出(FIFO)行为。

StackKeyedObjectPool : 实现了后进先出(LIFO)行为。

PoolableObjectFactory 定义了池化对象的生命周期方法,我们可以使用它分离被池化的不同对象和管理对象的创建,持久,销毁。

BasePoolableObjectFactory这个实现PoolableObjectFactory接口的一个抽象类,我们可用扩展它实现自己的池化工厂。

相关推荐

DNF纯净的黄金增幅书价格及作用详解
365bet在线体育投注网

DNF纯净的黄金增幅书价格及作用详解

📅 12-30 👁️ 6509
暗黑3 什么装备好用 全实用装备盘点
365bet网址搜索器

暗黑3 什么装备好用 全实用装备盘点

📅 07-20 👁️ 1128
pp助手安装失败 pp助手常见问题
365bet在线体育投注网

pp助手安装失败 pp助手常见问题

📅 10-18 👁️ 4544
挂全家福的最佳位置图,全家福不宜挂这些地方
365bet网址搜索器

挂全家福的最佳位置图,全家福不宜挂这些地方

📅 10-10 👁️ 2068
睡了别人老婆,对方老公要求赔偿合法吗?
365体育app

睡了别人老婆,对方老公要求赔偿合法吗?

📅 07-21 👁️ 515
【問題】GTAV意外退出了。 @俠盜獵車手 系列 哈啦板
365bet在线体育投注网

【問題】GTAV意外退出了。 @俠盜獵車手 系列 哈啦板

📅 08-29 👁️ 9406