ThreadLocal与对象重用
大家知道,java的内存管理机制是依靠垃圾收集器来完成的,其原理主要是对每一个线程作引用的有向图遍历,这种方式比起perl等完全依靠引用计数的语言来讲更为复杂,运算量也更多。由于这个机制,也造成了java编成风格上的内存浪费(不是泄漏)非常普遍。比如大量的局部Object变量的创建,什么时候想用了,就new 一个。这当然无可厚非,但是,高效率,不间断,要求减少垃圾收集的次数对于一些特定的实时系统来讲是非常有意义的。对象重用便是一个很好的解决方法。
这里我们不介绍对象池,如Jakarta Object Pool等的相对复杂的对象重用机制。而是介绍一种非常简单的重用方法。这个方法的思路只有一点,就是每一个线程对于每一个需要重用的对象的类拥一个实例。这样的好处是:
1,对象少,每一种类的对象数与线程数相同。
2,不用同步,没有效率上的问题。
实现的手段非常简单,就是利用ThreadLocal类。ThreadLocal类保证了每一个线程拥有不同的实例,而同一个线程一定是同一个实例。
这是我写的一个简单的重用对象工厂类,对于StringBuffer,List等常用的临时变量类型,都可以直接用getObject方法得到本线程中的实例,然后调用clear()或其他方法初始化一下就可以用了。但是必须注意,这个Object一定是临时的,其生存期不能超出其定义所在的方法,千万不能放到全局的数据结构或容器中。
import java.util.*;
/**
*
* @author lie.xiao
*/
public class ThreadLocalObjFactory {
private static Hashtable resourceTable = new Hashtable();
public static Object getObject(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
return getObject(className, null);
}
public static Object getObject(String className, ClassLoader loader) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (resourceTable.containsKey(className)) {
ThreadLocal threadLocal = (ThreadLocal)resourceTable.get(className);
Object o = threadLocal.get();
if (o == null) {
if (loader == null) {
o = Class.forName(className).newInstance();
} else {
loader.loadClass(className).newInstance();
}
threadLocal.set(o);
}
return o;
} else {
ThreadLocal threadLocal = new ThreadLocal();
Object o = null;
if (loader == null) {
o = Class.forName(className).newInstance();
} else {
loader.loadClass(className).newInstance();
}
threadLocal.set(o);
resourceTable.put(className, threadLocal);
return o;
}
}