来自http://www.iteye.com/topic/103804
(上接正确理解ThreadLocal(1) )
可以看到ThreadLocal类中的变量只有这3个int型:
- private final int threadLocalHashCode = nextHashCode();
- private static int nextHashCode = 0 ;
- private static final int HASH_INCREMENT = 0x61c88647 ;
而作为ThreadLocal实例的变量只有 threadLocalHashCode 这一个,nextHashCode 和HASH_INCREMENT 是ThreadLocal类的静态变量,实际上HASH_INCREMENT是一个常量,表示了连续分配的两个ThreadLocal实例的threadLocalHashCode值的增量,而nextHashCode 的表示了即将分配的下一个ThreadLocal实例的threadLocalHashCode 的值。
可以来看一下创建一个ThreadLocal实例即new ThreadLocal()时做了哪些操作,从上面看到构造函数ThreadLocal()里什么操作都没有,唯一的操作是这句:
- private final int threadLocalHashCode = nextHashCode();
那么nextHashCode()做了什么呢:
- private static synchronized int nextHashCode() {
- int h = nextHashCode;
- nextHashCode = h + HASH_INCREMENT;
- return h;
- }
因此ThreadLocal实例的变量只有这个threadLocalHashCode,而且是final的,用来区分不同的ThreadLocal实例,ThreadLocal类主要是作为工具类来使用,那么ThreadLocal.set()进去的对象是放在哪儿的呢?
看一下上面的set()方法,两句合并一下成为
- ThreadLocalMap map = Thread.currentThread().threadLocals;
这个ThreadLocalMap 类是ThreadLocal中定义的内部类,但是它的实例却用在Thread类中:
- public class Thread implements Runnable {
- ......
- /* ThreadLocal values pertaining to this thread. This map is maintained
- * by the ThreadLocal class. */
- ThreadLocal.ThreadLocalMap threadLocals = null ;
- ......
- }
再看这句:
- if (map != null )
- map.set(this , value);
也就是将该ThreadLocal实例作为key,要保持的对象作为值,设置到当前线程的ThreadLocalMap 中,get()方法同样大家看了代码也就明白了,ThreadLocalMap 类的代码太多了,我就不帖了,自己去看源码吧。
写了这么多,也不知讲明白了没有,有什么不当的地方还请大家指出来。
jdk1.3、1.4、1.5是一样的,map都是放在每个线程中的,以threadLocal为key,所不同的是,在1.3中这个map是个普通的HashMap,而1.4和1.5中是个ThreadLocalMap类,一个明显的特征是其中的Entry用到了弱引用WeakReference 类,但我感觉这个WeakReference的用法在这里并不能起到应有的作用。
另外想到一个把map放到各自线程中带来的好处是 因为各线程访问的map是各自不同的map,所以不需要同步,速度会快些;而如果把所有线程要用的对象都放到一个静态map中的话 多线程并发访问需要进行同步。
ThreadLocal主要是提供了保持对象的方法和避免参数传递地方便的对象访问方式。