码迷,mamicode.com
首页 > 其他好文 > 详细

我对ThreadLocal的理解

时间:2015-08-15 06:46:08      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:d

声明:小弟菜狗一个,对ThreadLocal的描述和理解难免有所偏差

        最近因为需要深入的了解android的handler消息机制而去查看了Looper的源码。众所周知在主线程中是不需要在程序员在代码新建一个Looper对象的,因为在主线程创建时它就被创建出来了。所以就好奇它是怎么被创建出来的然后发现它跟ThreadLocal 有关于是便查看了该类的一些资料,但还是不太理解。于是便尝试自己去看一下源码,然后就有了对ThreadLocal一个重新的认识。先贴出Looper的代码:

        

   private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

       

public class Looper {
    private static final boolean DEBUG = false;
    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;

    // sThreadLocal.get() will return null unless you've called prepare().
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
   
//该方法其实就是将一个Looper对象设置进ThreadLocal的一个map中
public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
</pre><pre name="code" class="java">
</pre><p></p><p>以上是Looper的代码,从代码中看出sThreadLocal是Looper的成员变量,它被new出来了。当我第一次看到此代码的时候便产生了一个疑问,不是说ThreadLocal对象都会绑定到一个线程当中去的吗,若这么创建对象那么如何确定它绑定到那一个线程中呢(到后来我发现我这种想法是不对的),于是我便查看了ThreadLocal的代码。首先因为pepare调用到ThreadLocal的set方法,我们先去查看下该方法的实现</p><p></p><pre name="code" class="java">    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//ThreadLocalMap是ThreadLocal的内部类
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

由ThreadLocal的方法不难看出set方法设置的值最后会与本ThreadLocal对象凑成一个键值对存放到它新建的ThreadLocalMap对象中的。此时会注意到两个方法getMap(ThreadLocal tl,T t)和createMap(Thread t, T t)。通过方法名就不难得出此两方法是跟ThreadLocalMap对象的获取和创建有关。下面先观察ThreadLocal类中createMap方法的代码

 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

通过代码可以知道此方法将一个新建的“键值对”为本ThreadLocal对象和要设置的value值的ThreadLocalMap对象赋值给当前线程的threadLocals变量。接下来查看Thread的代码。

  /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
可见它是Thread的一个成员变量。至此当前线程的threadLocals就不为空而且是不会再被改变(因为从ThreadLocal的set方法中每一次在设置当前threadLocals的值之前都会先判断该对象是否为null)。


通过观察这一系列的代码可以了解到其实在每一个线程中都会有一个ThreadLocal.ThreadLocalMap变量,它与Map有点类似用于存放键值对,不过它的键是ThreadLocal对象,所以一个ThreadLocal对象只能在它所在线程的ThreadLocal.ThreadLocalMap对象对象中存放有自己是key的一个值。其实此时又会产生一个疑问这样的以ThreadLocal

为key的键值对存放到Thread对象中的ThreadLocal.ThreadLocalMap中有什么意义呢?因为当我们失去了ThreadLocal对象之后就不能取出在线程中以该ThreadLocal的对应值。其实通过观察Looper的代码不难看出它的ThreadLocal sThreadLocal对象是一个静态变量,因此所有的Looper对象都在“共用”一个ThreadLocal 对象。因此确保了不同Looper的Looper.prepare方法在同一个线程的ThreadLocal.ThreadLocalMap中对应的值是一样的,这确保了一个线程中只有一个Looper对象存放在当前线程的ThreadLocal.ThreadLocalMap中。




       

版权声明:本文为博主原创文章,未经博主允许不得转载。

我对ThreadLocal的理解

标签:d

原文地址:http://blog.csdn.net/kidd1991/article/details/47667917

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!