对象池化技术
对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。
对于没有状态的对象(例如String),在重复使用之前,无需进行任何处理;对于有状态的对象(例如StringBuffer),在重复使用之前,就需要把它们恢复到等同于刚刚生成时的状态。由于条件的限制,恢复某个对象的状态的操作不可能实现了的话,就得把这个对象抛弃,改用新创建的实例了。
并非所有对象都适合拿来池化——因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。
什么时候不要池化
采用对象池化的本意,是要通过减少对象生成的次数,减少花在对象初始化上面的开销,从而提高整体的性能。然而池化处理本身也要付出代价,因此,并非任何情况下都适合采用对象池化。
对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化;
对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度);
对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。
根据使用方法的不同,实际的情况可能与这一测量结果略有出入。在配置较高的机器和技术较强的虚拟机上,不宜池化的对象的范围可能会更大。不过,对于像网络和数据库连接这类重量级的对象来说,目前还是有池化的必要。
基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。
对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。用于充当保存对象的“容器”的对象,被称为“对象池”(Object Pool,或简称Pool)。
对于没有状态的对象(例如String),在重复使用之前,无需进行任何处理;对于有状态的对象(例如StringBuffer),在重复使用之前,就需要把它们恢复到等同于刚刚生成时的状态。由于条件的限制,恢复某个对象的状态的操作不可能实现了的话,就得把这个对象抛弃,改用新创建的实例了。
并非所有对象都适合拿来池化——因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。
什么时候不要池化
采用对象池化的本意,是要通过减少对象生成的次数,减少花在对象初始化上面的开销,从而提高整体的性能。然而池化处理本身也要付出代价,因此,并非任何情况下都适合采用对象池化。
对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化;
对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度);
对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。
根据使用方法的不同,实际的情况可能与这一测量结果略有出入。在配置较高的机器和技术较强的虚拟机上,不宜池化的对象的范围可能会更大。不过,对于像网络和数据库连接这类重量级的对象来说,目前还是有池化的必要。
基本上,只在重复生成某种对象的操作成为影响性能的关键因素的时候,才适合进行对象池化。如果进行池化所能带来的性能提高并不重要的话,还是不采用对象池化技术,以保持代码的简明,而使用更好的硬件和更棒的虚拟机来提高性能为佳。
在Java中可以自定义或者借用第三方类库(如:apache commons-pool)实现对象池
以下是我自己实现的对象池,相当粗糙
思路是:
线程池中有两个集合,一个集合A存放空闲中的对象,一个集合B存放使用中的对象,
线程从A中拿到对象使用,并放入B中,当线程使用完对象之后从B中取出放回A中,
有状态的对象在使用之前先恢复为初始化状态,
当线程池中所有的对象都是使用中时(即都属于集合B),线程等待,当有线程返还对象时,线程唤醒。
001 | package common.pool; |
002 |
003 | import java.lang.reflect.Field; |
004 | import java.util.Collections; |
005 | import java.util.HashSet; |
006 | import java.util.Iterator; |
007 | import java.util.Set; |
008 |
009 | /** |
010 | * |
011 | * @author JiaZhiTang |
012 | *自定义对象池 |
013 | */ |
014 | @SuppressWarnings ({ "unchecked" , "hiding" }) |
015 | public class DIYObjectPool<E> { |
016 | private Set<Object> activeSet = Collections.synchronizedSet( new HashSet<Object>()); //正在被使用的对象的集合,已被同步 |
017 | private Set<Object> idleSet = Collections.synchronizedSet( new HashSet<Object>()); //空闲的对象的集合,已被同步 |
018 | |
019 | private Integer maxObjetc = 100 ; //最大对象数,默认值100 |
020 | private Class<E> cls; //对象池 的类,因为java不能 直接使用泛型创建对象 T t = new T(); |
021 | private Object lock = new Object(); //线程等待监视器 |
022 |
023 |
024 | /** |
025 | * 构造方法 |
026 | * @param maxObjetc |
027 | * @param cls |
028 | */ |
029 | public DIYObjectPool(Integer maxObjetc, Class<E> cls) { |
030 | this .maxObjetc = maxObjetc; |
031 | this .cls = cls; |
032 | } |
033 |
034 | /** |
035 | * 从线程池中取出对象 |
036 | * @param <E> |
037 | * @return |
038 | * @throws Exception |
039 | */ |
040 | public synchronized <E> E borrowObject() throws Exception{ |
041 | Object obj = null ; |
042 | if (idleSet.size()> 0 ){ |
043 | Iterator<Object> iterator = idleSet.iterator(); |
044 | obj = iterator.next(); |
045 | } |
046 | if (obj != null ){ |
047 | idleSet.remove(obj); |
048 | activeSet.add(obj); |
049 | } else { |
050 | int size = activeSet.size()+idleSet.size(); |
051 | if (size>=maxObjetc){ |
052 | synchronized (lock) { |
053 | System.out.println( "-----池中无对象,线程等待-----" ); |
054 | lock.wait(); |
055 | } |
056 | return borrowObject(); |
057 | } else { |
058 | obj = cls.newInstance(); |
059 | activeSet.add(obj); |
060 | } |
061 | } |
062 | |
063 | System.out.println( "池中总对象数: " +(activeSet.size()+idleSet.size())+ " ,使用中:" +activeSet.size()+ " ,空闲中:" +idleSet.size()); |
064 | |
065 | clearObject(obj); //有状态对象恢复默认初始化 |
066 | return (E)obj; |
067 | } |
068 | |
069 | /** |
070 | * 对象使用完毕,返还线程池 |
071 | * @param obj |
072 | */ |
073 | public void returnObject(Object obj){ |
074 | if (obj != null ){ |
075 | activeSet.remove(obj); |
076 | idleSet.add(obj); |
077 | synchronized (lock) { |
078 | System.out.println( "唤醒等待线程" ); |
079 | lock.notify(); |
080 | // lock.notifyAll(); |
081 | } |
082 | |
083 | } |
084 | } |
085 |
086 |
087 | /** |
088 | * 有状态对象恢复默认初始化 |
089 | * @param obj |
090 | */ |
091 | public void clearObject(Object obj) throws Exception{ |
092 | Class<?> cls = obj.getClass(); |
093 | Field[] fields = cls.getDeclaredFields(); |
094 | for (Field field : fields) { |
095 | field.setAccessible( true ); |
096 | field.set(obj, null ); |
097 | } |
098 | } |
099 |
100 |
101 | public static void main(String[] args) throws Exception { |
102 | //初始化线程池 |
103 | int max = 1000 ; |
104 | DIYObjectPool<Object> pool = new DIYObjectPool<Object>(max,Object. class ); |
105 | |
106 | //自定义运行线程 |
107 | class TestThread extends Thread{ |
108 | DIYObjectPool objectPool; |
109 |
110 | public TestThread(DIYObjectPool objectPool) { |
111 | this .objectPool = objectPool; |
112 | } |
113 | |
114 | @Override |
115 | public void run() { |
116 | try { |
117 | Object obj = objectPool.borrowObject(); |
118 | Thread.sleep( 3000 ); //假设对象被一个线程使用的3秒钟 |
119 | objectPool.returnObject(obj); |
120 | } catch (Exception e) { |
121 | e.printStackTrace(); |
122 | } |
123 | } |
124 | } |
125 | |
126 | //并发max*2个线程 |
127 | max = max* 2 ; |
128 | for ( int i = 0 ; i < max; i++) { |
129 | new TestThread(pool).start(); |
130 | } |
131 | } |
132 | |
133 | } |
工厂类
01 | package common.pool; |
02 |
03 | import org.apache.commons.pool.PoolableObjectFactory; |
04 |
05 | @SuppressWarnings ({ "unchecked" }) |
06 | public class ObjectPoolFactory implements PoolableObjectFactory { |
07 |
08 | private Class cls; |
09 | private static final String INIT_METHOD = "clearObject" ; //有状态对象恢复初始化的方法 |
10 | |
11 | |
12 | public ObjectPoolFactory(Class cls) { |
13 | this .cls = cls; |
14 | } |
15 |
16 | public void activateObject(Object arg0) throws Exception { |
17 | System.out.println( "有状态对象恢复初始化" ); |
18 | try { |
19 | cls.getDeclaredMethod(INIT_METHOD).invoke(arg0); //有状态对象恢复初始化 |
20 | } catch (Exception e) { |
21 | } |
22 | } |
23 |
24 | public void destroyObject(Object arg0) throws Exception { |
25 | |
26 | } |
27 |
28 | public Object makeObject() throws Exception { |
29 | System.out.println( "创建新对象" ); |
30 | return cls.newInstance(); //创建新对象 |
31 | } |
32 |
33 | public void passivateObject(Object arg0) throws Exception { |
34 | |
35 | } |
36 |
37 | public boolean validateObject(Object arg0) { |
38 | return false ; |
39 | } |
40 |
41 | } |
对象池
01 | package common.pool; |
02 |
03 | import org.apache.commons.pool.impl.GenericObjectPool; |
04 |
05 |
06 | @SuppressWarnings ({ "unchecked" }) |
07 | public class ObjectPool { |
08 | |
09 | private GenericObjectPool pool; |
10 | |
11 | public ObjectPool(Class cls) { |
12 | this .pool = new GenericObjectPool( new ObjectPoolFactory(cls)); |
13 | pool.setMaxActive( 2 ); //最大活动对象 |
14 | pool.setMaxIdle( 1 ); //最大空闲对象 |
15 | pool.setMaxWait( 100000 ); //最大等待时间 |
16 | } |
17 | |
18 | /** |
19 | * 池中取出对象 |
20 | * @param <T> |
21 | * @return |
22 | */ |
23 | public <T> T borrowObject(){ |
24 | T obj = null ; |
25 | try { |
26 | obj = (T)pool.borrowObject(); |
27 | System.out.println( "获得对象" ); |
28 | } catch (Exception e) { |
29 | System.out.println(e); |
30 | } |
31 | return obj; |
32 | } |
33 | |
34 | /** |
35 | * 对象放回池中 |
36 | * @param obj |
37 | */ |
38 | public void returnObject(Object obj){ |
39 | try { |
40 | pool.returnObject(obj); |
41 | System.out.println( "返还对象" ); |
42 | } catch (Exception e) { |
43 | System.out.println(e); |
44 | } |
45 | } |
46 | |
47 | } |
测试
01 | package common.pool; |
02 |
03 | public class Test { |
04 | |
05 | public static ObjectPool pool = new ObjectPool(Object. class ); |
06 |
07 | public static void main(String[] args) { |
08 | for ( int i = 0 ; i < 2000 ; i++) { |
09 | new Thread(){ |
10 | public void run() { |
11 | Object obj = Test.pool.borrowObject(); |
12 | System.out.println(obj.toString()); |
13 | try { |
14 | Thread.sleep( 1000 ); |
15 | } catch (Exception e) { |
16 | } |
17 | Test.pool.returnObject(obj); |
18 | }; |
19 | }.start(); |
20 | } |
21 | } |
22 |
23 | } |
这里依赖于 commons-pool-1.5.6.jar