对象池化,对象池
对象池化技术
对象池化的基本思路是:创建多个对象并管理,使用时借出对象,用完归还对象,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(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; /** * *自定义对象池 */ @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(); } } }
同步锁,线程阻塞,会大大的影响并发的效率,是否可以用循环来请求对象池的对象,回收对象,可以使用commons-pool
第一步:创建对象工厂类继承BasePoolableObjectFactory类或实现PoolableObjectFactory接口
package org.apache.commons.pool; public abstract interface PoolableObjectFactory<T> { public abstract T makeObject() throws Exception; public abstract void destroyObject(T paramT) throws Exception; public abstract boolean validateObject(T paramT); public abstract void activateObject(T paramT) throws Exception; public abstract void passivateObject(T paramT) throws Exception; }
实现上面的方法
makeObject() 生成对象
destroyObject(T paramT) 销毁对象
validateObject(T paramT) 验证对象是否有效
activateObject(T paramT) 激活对象
passivateObject(T paramT) 钝化对象
活化(Activate)与钝化(Passivate) 是Web容器为了更好的利用系统资源或者进行服务器负载平衡等原因而对特定对象采取的措施。
makeObject() destroyObject(T paramT) validateObject(T paramT) 我自己只实现了这3个方法,具体实现看实际需求
第二步,使用GenericObjectPool<T>的处理对象
需要用到两个对象,一个是第一步的factory对象,另一个是conf对象是GenericObjectPool的内部类(有默认值,可自己自定义类修改参数)。
封装GenericObjectPool对象,使用GenericObjectPool的
borrowObject() 借出对象,对象池对象的使用
returnObject(resource) 归还对象
invalidateObject(resource) 验证对象
close() 关闭对象池
使用封装的对象就可以使用对象池了,可以使用spring注入GenericObjectPool<T>,注入参数factory和conf
部分内容摘自:http://www.java9527.com/forum.php?mod=viewthread&tid=5&fromuid=1
作者:fenglie
专注于JAVAEE开发,热爱开源项目
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。