首页 > 代码库 > 弄明白ThreadLocal类

弄明白ThreadLocal类

1ThreadLocal类的由来

因为有问题,人类就会想法设法的创造一些东西出来解决问题,嗯,这句话同意吧。

假如目前有这么一个问题:有个家庭,三个孩子都想看妈妈买的一本童话书,但是只有一本书,该如何是好?

方法一:家里没钱买第二本了,那就排队看,谁跑得快来到妈妈面前的就先看。后面来晚的,候着等着。等前面的看完再到你。于是以时间换空间的synchronized类出现了。

 

方法二:多大的事儿,你们爸爸有钱,随便任性。立马再买两本一模一样的,人手一本。于是以空间换时间的ThreadLocal类出现了。

 

看到这里,你应该明白了,两个类都是为了解决多线程的同步竞争问题而产生的。内存空间不够宽裕的会选择用synchronized类,而内存充足而注重时间的会选择ThreadLocal类。

 

2、含义

我一开始以为都是本地线程,望文生义,其实,不对的。它不是一个线程,它只不过是线程的一个局部变量而已。

 

但是它存在的意义却是为使用它的线程提供独立的变量副本。

通过上面的故事可知,ThreadLocal类为每个线程提供了一份仅仅属于该线程的变量拷贝,使得该线程不必和其他线程相争。

 

3、实现原理

ThreadLocal类是通过它的一个set()方法来为一个线程提供变量副本的。那么我们可以通过set()方法的源码来了解其实现原理

 

    public void set(T value) {
        Thread t = Thread.currentThread(); //得到当前执行的线程,
//currentThread()是native方法,指向底层C/C++实现的方法。  public static native Thread currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


下面解释代码——

ThreadLocalMap map = getMap(t);  // getMap(t)ThreadLocal类局部方法,返回的是该线程的一个map,ThreadLocalMap 。没听过ThreadLocalMap 这个,应该知道hashMap吧,ThreadLocalMap 实现原来和HashMap差不多,我就把它当做特殊的hashMap。ThreadLocalMap 类是ThreadLocal类的一个静态内部类,在ThreadLocal.class 242行开始,


ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

        ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }


ThreadLocalMap 的key就是当前的ThreadLocal对象,而value就是你所需要复制另存的副本对象了,比如说故事中那本书。

 

那么后面的

 if (map != null)
            map.set(this, value);
        else
            createMap(t, value);

就很明显了,用一个ThreadLocalMap 来保存变量副本。没有则创建一个map。反正必须有一个map。我不管。

由于当前的ThreadLocal是线程的一个私有静态成员变量,所以是该线程唯一的,那么以它为键值存储的数据必然也只能是唯一,并且由于查找时通过key来查找的,因为也只能是被该线程来使用。因此实现了独立的副本。

 

4、疑问

这样以空间换时间方法能不能在内存空间充足情况下完全替代同步方法呢?答案是否定的。因为对于不能复制,永远只有一份的东西,你即使再有能力也不能改变。比如某些对象它的实例化只能单例实例化,只有一个。那么你就只能用同步方法了。


辅助资料:

http://www.iteye.com/topic/1007515 

http://blog.csdn.net/kjfcpua/article/details/8671601


弄明白ThreadLocal类