首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入分析Java的ThreadLocal

深入分析Java的ThreadLocal

作者头像
PhoenixZheng
发布2018-08-07 16:50:39
2500
发布2018-08-07 16:50:39
举报

上回书说,Android可以用Looper+Handler来实现线程通信的关键是在于Looper 回顾:深入了解Android的Looper Looper 在当前线程里维护了一个MessageQueue,并不断从中取Message出来给Handler去处理。 我们留了个问题,Looper是个全局类,它通过ThreadLocal来保证每个线程只能获取到自己的Looper,那么它是怎么做到的呢?

Java之ThreadLocal

ThreadLocal是java.lang包下的类,它是一个用来创建线程局部变量的类。先来看一段代码,

final ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test threadlocal");
new Thread(){
    @Override
    public void run() {
        Log.d(TAG, "value: " + threadLocal.get());
    }
}.start();

这段代码其实打印不出threadlocal中的内容,而是直接输出null

:D/ThreadLocal value: null

因为我们是在另外一个线程中set的数据,因此在新线程中是读不到这个值的。 Looper同理,sThreadLocal在初始化时以Looper作为泛型,每当我们调用prepare()时,都会实例化一个Looper并放入sThreadLocal中,因为这个Looper是在当前线程创建的,所以当我们在这个线程中调用myLooper()时,也只能从sThreadLocal获取到当前线程的Looper。

ThreadLocal的实现

一般面试时能了解到这个层面基本算中高级工程师了,当然如果要到高级或者资深,就不得不了解更深一层的原理实现。 ThreadLocal的实现Java和Android略有不同,但原理相差无二。我们可以从 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);
}

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

ThreadLocalMap 是ThreadLocal的内部类。这段代码可以看出当进行set()操作时,实际是获取当前线程的ThreadLocalMap对象并放入值。所以只能在本线程中访问,其他线程无法访问。

ThreadLocal进阶

到这里基本上对于ThreadLocal的知识点就结束了,你已经是高级程序员了。接下来的进阶部分可以让你成为资深开发。 作为一个习惯性找bug的优秀程序员,会想是否可以访问其他线程的ThreadLocal里的数据呢?答案当然是可以的。

InheritableThreadLocal

如果在ThreadLocal实例化的时候使用的是它的子类 InheritableThreadLocal,那么输出结果就会变成

final ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
threadLocal.set("test threadlocal");
new Thread(){
    @Override
    public void run() {
        Log.d(TAG, "value: " + threadLocal.get());
    }
}.start();

:D/ThreadLocal value: test threadlocal

原因是,线程创建过程中,会把父线程的inheritableThreadLocals对象复制一份放到子线程的inheritableThreadLocals,当我们用 InheritableThreadLocal的实例的get和set方法时,其实读取的是复制过后的值,所以它保留了父线程的数据。有兴趣的可以看下Thread的源码,

private void init2(Thread parent) {
    ....
    if (parent.inheritableThreadLocals != null) {
        this.inheritableThreadLocals = ThreadLocal.createInheritedMap(
                parent.inheritableThreadLocals);
    }
}
总结

· Looper使用了Java的ThreadLocal类,来保证每个线程只和当前线程创建的Looper绑定 · ThreadLocal的对象实际上是保存在Thread中,因此每个线程对Looper的获取只能获取到自己的Looper 到这里我们就结束了对Android线程交互的分析啦,希望面试时对大家有帮助~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java之ThreadLocal
  • ThreadLocal的实现
  • ThreadLocal进阶
    • InheritableThreadLocal
    • 总结
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档