Android-ThreadLocal解析

ThreadLocal分析

Handler的运行需要MessageQueue和Looper的支持,如果您对这方面不是很熟悉,那么我推荐您阅读这个,或者看Android开发艺术探索,而为了更好的理解Looper,那么ThreadLocal是避不过去的一项

我们都知道,一个线程只能创建一个Looper,那么在这个线程中传递数据的就是ThreadLocal了

ThreadLocal是一个线程内部的数据存储类,他可以在指定的线程中存储数据,然后当然也只能在存储数据的线程来获取数据,来看一个小demo

首先我们定义一个ThreadLocal对象,然后分别在主线程和两个子线程中去设置数据和获取数据

private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    mBooleanThreadLocal.set(true);
    Log.d("112233", Thread.currentThread().getName()
            + " = " + 
            mBooleanThreadLocal.get());

    new Thread("Thread #1"){
        @Override
        public void run() {
            super.run();
            mBooleanThreadLocal.set(false);
            Log.d("112233", Thread.currentThread().getName()
                    + " = " + 
                    mBooleanThreadLocal.get());
        }
    }.start();

    new Thread("Thread #2"){
        @Override
        public void run() {
            super.run();
            Log.d("112233", Thread.currentThread().getName()
                    + " = " + 
                    mBooleanThreadLocal.get());
        }
    }.start();
}

可以看到这里用的都是同一个LocalThread对象,然后运行程序,看一下log

D/112233: main = true
D/112233: Thread #1 = false
D/112233: Thread #2 = null

我们会发现在不同的线程中获得的值是不同的,下面来分析一下源码,来看一下为什么返回的值不一样

public T get() {
    Thread t = Thread.currentThread();//从这里获取当前线程
    ThreadLocalMap map = getMap(t);//这里获取当前线程的Map
    if (map != null) {
        //这里取出由当前threadLocal为key的entry
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;//返回value
    }
    return setInitialValue();//如果为空,那么初始化
}

-------------------------------------------

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;//这里返回多个threadLocal的对象
}

-------------------------------------------

private T setInitialValue() {
    T value = initialValue();//这个方法返回null
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);//如果map存在,则替换掉数据
    else
        createMap(t, value);//如果map不存在,则创建一个map,数据为null
    return value;//最后返回null
}

从get方法我们可以看得出来获取数据是用Thread为参数的,所以说每个线程的数据都不一样。既然这样我们就再来看看set方法

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

我们会发现和上面的setInitialValue()方法差不多,都是调用的map.set()方法,这个方法其实就是一个以当前ThreadLocal为key存储的过程,我们就不细细的去研究了,有兴趣的可以去看一下

至此这个ThreadLocal我们也就研究的差不多了,其实的就是在不同的线程存储不同的数据

ThreadLocal和InheritableThreadLocal

我第一次写那个小demo的时候犯了一个小错误,new对象的时候new成了InheritableThreadLocal,从名字我们也可以看得出来这是一个继承了table的ThreadLocal,关于这两个有什么区别,我推荐您看这个

爱小丽,爱Android

    原文作者:爱小丽
    原文地址: https://www.jianshu.com/p/6ba6e66352f7
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞