对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。
对于没有状态的对象(例如String),在重复使用之前,无需进行任何处理;对于有状态的对象(例如StringBuffer),在重复使用之前,就需要把它们恢复到等同于刚刚生成时的状态。由于条件的限制,恢复某个对象的状态的操作不可能实现了的话,就得把这个对象抛弃,改用新创建的实例了。
并非所有对象都适合拿来池化——因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。
什么时候不要池化
采用对象池化的本意,是要通过减少对象生成的次数,减少花在对象初始化上面的开销,从而提高整体的性能。然而池化处理本身也要付出代价,因此,并非任何情况下都适合采用对象池化。
对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化;
对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度);
对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。
根据使用方法的不同,实际的情况可能与这一测量结果略有出入。在配置较高的机器和技术较强的虚拟机上,不宜池化的对象的范围可能会更大。不过,对于像网络和数据库连接这类重量级的对象来说,目前还是有池化的必要。
基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。
在Java中可以自定义或者借用第三方类库(如:apache commons-pool)实现对象池
以下是我自己实现的对象池,相当粗糙
思路是:
线程池中有两个集合,一个集合A存放空闲中的对象,一个集合B存放使用中的对象,
线程从A中拿到对象使用,并放入B中,当线程使用完对象之后从B中取出放回A中,
有状态的对象在使用之前先恢复为初始化状态,
当线程池中所有的对象都是使用中时(即都属于集合B),线程等待,当有线程返还对象时,线程唤醒。
package common.pool;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
*
* @author JiaZhiTang
*自定义对象池
*/
@SuppressWarnings({"unchecked","hiding"})
public class DIYObjectPool<E> {
private Set<Object> activeSet = Collections.synchronizedSet(new HashSet<Object>());//正在被使用的对象的集合,已被同步
private Set<Object> idleSet = Collections.synchronizedSet(new HashSet<Object>());//空闲的对象的集合,已被同步
private Integer maxObjetc = 100;//最大对象数,默认值100
private Class<E> cls;//对象池 的类,因为java不能 直接使用泛型创建对象 T t = new T();
private Object lock = new Object();//线程等待监视器
/**
* 构造方法
* @param maxObjetc
* @param cls
*/
public DIYObjectPool(Integer maxObjetc, Class<E> cls) {
this.maxObjetc = maxObjetc;
this.cls = cls;
}
/**
* 从线程池中取出对象
* @param <E>
* @return
* @throws Exception
*/
public synchronized <E> E borrowObject() throws Exception{
Object obj = null;
if(idleSet.size()>0){
Iterator<Object> iterator = idleSet.iterator();
obj = iterator.next();
}
if(obj != null){
idleSet.remove(obj);
activeSet.add(obj);
}else{
int size = activeSet.size()+idleSet.size();
if(size>=maxObjetc){
synchronized (lock) {
System.out.println("-----池中无对象,线程等待-----");
lock.wait();
}
return borrowObject();
}else{
obj = cls.newInstance();
activeSet.add(obj);
}
}
System.out.println("池中总对象数: "+(activeSet.size()+idleSet.size())+" ,使用中:"+activeSet.size()+" ,空闲中:"+idleSet.size());
clearObject(obj);//有状态对象恢复默认初始化
return (E)obj;
}
/**
* 对象使用完毕,返还线程池
* @param obj
*/
public void returnObject(Object obj){
if(obj != null){
activeSet.remove(obj);
idleSet.add(obj);
synchronized (lock) {
System.out.println("唤醒等待线程");
lock.notify();
// lock.notifyAll();
}
}
}
/**
* 有状态对象恢复默认初始化
* @param obj
*/
public void clearObject(Object obj) throws Exception{
Class<?> cls = obj.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
field.set(obj, null);
}
}
public static void main(String[] args) throws Exception {
//初始化线程池
int max = 1000;
DIYObjectPool<Object> pool = new DIYObjectPool<Object>(max,Object.class);
//自定义运行线程
class TestThread extends Thread{
DIYObjectPool objectPool;
public TestThread(DIYObjectPool objectPool) {
this.objectPool = objectPool;
}
@Override
public void run() {
try {
Object obj = objectPool.borrowObject();
Thread.sleep(3000);//假设对象被一个线程使用的3秒钟
objectPool.returnObject(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//并发max*2个线程
max = max*2;
for (int i = 0; i < max; i++) {
new TestThread(pool).start();
}
}
}
工厂类
package common.pool;
import org.apache.commons.pool.PoolableObjectFactory;
@SuppressWarnings({"unchecked"})
public class ObjectPoolFactory implements PoolableObjectFactory {
private Class cls;
private static final String INIT_METHOD = "clearObject";//有状态对象恢复初始化的方法
public ObjectPoolFactory(Class cls) {
this.cls = cls;
}
public void activateObject(Object arg0) throws Exception {
System.out.println("有状态对象恢复初始化");
try {
cls.getDeclaredMethod(INIT_METHOD).invoke(arg0);//有状态对象恢复初始化
} catch (Exception e) {
}
}
public void destroyObject(Object arg0) throws Exception {
}
public Object makeObject() throws Exception {
System.out.println("创建新对象");
return cls.newInstance();//创建新对象
}
public void passivateObject(Object arg0) throws Exception {
}
public boolean validateObject(Object arg0) {
return false;
}
}
对象池
package common.pool;
import org.apache.commons.pool.impl.GenericObjectPool;
@SuppressWarnings({"unchecked"})
public class ObjectPool {
private GenericObjectPool pool;
public ObjectPool(Class cls) {
this.pool = new GenericObjectPool(new ObjectPoolFactory(cls));
pool.setMaxActive(2);//最大活动对象
pool.setMaxIdle(1);//最大空闲对象
pool.setMaxWait(100000);//最大等待时间
}
/**
* 池中取出对象
* @param <T>
* @return
*/
public <T> T borrowObject(){
T obj = null;
try {
obj = (T)pool.borrowObject();
System.out.println("获得对象");
} catch (Exception e) {
System.out.println(e);
}
return obj;
}
/**
* 对象放回池中
* @param obj
*/
public void returnObject(Object obj){
try {
pool.returnObject(obj);
System.out.println("返还对象");
} catch (Exception e) {
System.out.println(e);
}
}
}
测试
package common.pool;
public class Test {
public static ObjectPool pool = new ObjectPool(Object.class);
public static void main(String[] args) {
for (int i = 0; i < 2000; i++) {
new Thread(){
public void run() {
Object obj = Test.pool.borrowObject();
System.out.println(obj.toString());
try {
Thread.sleep(1000);
} catch (Exception e) {
}
Test.pool.returnObject(obj);
};
}.start();
}
}
}
这里依赖于 commons-pool-1.5.6.jar