ThreadLocale理解和对WeakReference的运用

来源:互联网 发布:百分百网络营销软件 编辑:程序博客网 时间:2024/05/16 14:43
 理论基础看其他收录的文章,这里记录的是自己的理解。 每个Thread都有一个成员变量ThreadLocal.ThreadLocalMap threadLocals = null;默认为空。 ThreadLocale中的get()方法:
public T get() {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null) {        ThreadLocalMap.Entry e = map.getEntry(this);        if (e != null)            return (T)e.value;    }    return setInitialValue();}ThreadLocalMap getMap(Thread t) {      return t.threadLocals;}getMap()方法获取了当前线程的threadLocals变量,是一个ThreadLocalMap对象,默认为空。ThreadLocale.set()的时候,才会对threadLocales赋值。public void set(T value) {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else        createMap(t, value);}
 可以说,Thread的threadLocals是专门为ThreadLocal而存在的。每次调用TheadLocal.get()的时候,其实是以ThreadLocal对象为key,每个使用到同一个ThreadLocal的线程拥有相同的ThreadLocal引用,但因为每个thread维护自己的threadLocals对象,所以,取到的数据是不同的,是线程私有的。 以前理解的,是通过当前thread为key,取对应的值的想法是错误的。 为什么这么设计呢?个人理解,如果使用一个map来存储thread和value的键值对。一个应用程序得有无穷尽个线程,而map的值又不会因为线程的销毁而销毁,很快就会因为thread过多,而又无法释放资源而耗尽内存。每个线程维护一个ThreadLocalMap<ThreadLocal,T>对象,每次线程销毁的时候,值跟着就销毁了,不会存在内存耗尽的情况。 再深入的想想,并不一定非得在每个Thread对象中拥有一个threadLocals变量。如果ThreadLocal中有个容器,使用WeakReference<Thread>来保存thread和value的键值对,并不定时的清空weakreference.get()==null的键值对。应该也能实现同样的同能。但是复杂了很多。 下面说说ThreadLocal对WeakReference的使用。 Thread的threadLocals变量是一个ThreadLocalMap对象,是ThreadLocal的内部类。ThreadLocalMap不是一个map对象,只是取名为map而已。通过table保存Entity对象,从而维护值。 static class Entry extends WeakReference<ThreadLocal> {     /** The value associated with this ThreadLocal. */     Object value;     Entry(ThreadLocal k, Object v) {         super(k);         value = v;     } } private Entry[] table; Entity继承WeakReference<ThreadLocal>,并且弱引用了key,即ThreadLocal对象。意味着,如果没有外部变量引用ThreadLocal对象,那么entity对象中的key将为null,value值不会被虚拟机销毁。这就是以下代码存在的原因:
private Entry getEntry(ThreadLocal key) {        int i = key.threadLocalHashCode & (table.length - 1);        Entry e = table[i];        if (e != null && e.get() == key)            return e;        else            return getEntryAfterMiss(key, i, e);}private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {        Entry[] tab = table;        int len = tab.length;    while (e != null) {        ThreadLocal k = e.get();        if (k == key)            return e;        if (k == null)            expungeStaleEntry(i);        else            i = nextIndex(i, len);        e = tab[i];    }    return null;}
   以前我以为,只要是被WeakReference引用的对象,在下一次gc()的时候就会被回收掉,这是不对的。还少了一个条件,就是WeakReference引用的对象不再被其他外部对象引用的时候,那么,WeakReference引用的对象在下一次gc()的时候就会被回收掉。 看看这段代码,ThreadLocal的经典实用方式,但这里面有一些以前没考虑到的地方。
private static final ThreadLocal threadSession = new ThreadLocal();     public static Session getSession() throws InfrastructureException {          Session s = (Session) threadSession.get();               try {        if (s == null) {            s = getSessionFactory().openSession();            threadSession.set(s);        }    } catch (HibernateException ex) {        throw new InfrastructureException(ex);    }    return s;}     }
 threadSession是一个类的静态成员变量,就是说threadSession在程序运行过程中,不会存在不被引用的情况,所以即使threadSession被WeakReference引用,但绝对不会被gc()销毁。因此不用考虑ThreadLocalMap的Entity的key==null的情况。 为什么ThreadLocalMap不是map? 个人理解,如果ThreadLocalMap是map,那么怎么让虚拟机销毁不再使用资源?虽然可以通过其他的技术手段来销毁,但毕竟增加了工作量,而jdk提供这么好用的WeakReference,为什么不使用呢?而且ThreadLocalMap是一个内部类,很明显,就是为了ThreadLocel而设计的。
0 0