美文网首页
ThreadLocal源码解析

ThreadLocal源码解析

作者: 琳子baby | 来源:发表于2018-08-16 11:11 被阅读40次

一、使用场景

ThreadLocal用于不同线程获取各自数据,同一个线程也可根据不同的threadlocal对象获取到各自的数据。

二、源码解析

ThreadLocal如何实现不同线程获取各自数据的呢?其实源码中使用到ThreadLocal的场景有很多,下面通过Looper来分析ThreadLocal的实现原理。

Android基于消息机制运行,每个线程都有自己的消息队列,通过Looper不断循环获取消息,进行操作。我们在不同线程中调用Looper.myLooper()可以获取到各自线程的Looper对象,我们没有传入线程的相关数据,那么是如何实现的呢?

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
 
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

很显然,通过ThreadLocal的get方法实现,我们继续看ThreadLocal

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
 
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
 
    return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

在ThreadLocal的get方法中首先获取了当前线程,接着获取到此线程的ThreadLocalMap对象,通过源码可以得知,它是数据存储类。好了,原来获取到的就是每个线程的数据存储类,当然可以实现不同线程获取各自的数据了。当我们获取到ThreadLocalMap之后,接下来就要取出其中的value,也就是Looper,这里有两个分支。

 if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
}

当map不为null时,当前的ThreadLocal作为key,获取value,所以(划重点)ThreadLocal不只可以实现存储不同线程的数据,也可以实现存储同一线程中不同ThreadLocal对象的数据。
当map为null时,首先获取初识value,默认是null,可以自己重写initialValue赋值,接着调用creatMap

private T setInitialValue() {
    T value = initialValue();
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}

获取当前线程的ThreadLocalMap存储对象,并将当前ThreadLocal对象作为key,赋值初始的value。

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

调用createMap只有两个地方,set和setInitialValue,下面我们来看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,若map不为null,则将当前ThreadLocal对象作为key,添加value,若为null,则创建ThreadLocalMap。

我们回到Looper,调用set的只有一个地方,就是prepare,主线程即UI线程会自动调用prepare,将Looper对象作为value放置到主线程的ThreadLocalMap中;所以这就是为什么子线程使用Looper时候,先手动调用prepare的原因了。

三、总结

1、在各自线程中创建其数据存储类ThreadLocalMap,并赋值给线程中的变量threadLocals;获取数据时,直接取出当前线程的threadLocals,即获得此线程的数据存储类。所以不同线程可获取到各自的数据。

2、由于ThreadLocalMap以当前ThreadLocal作为key,所以也可实现同一线程的不同ThreadLocal对象获取到各自的数据。

相关文章

  • Netty 源码分析-目录

    Netty源码分析1 - Promise异步框架的设计Netty源码分析2 - ThreadLocal 源码解析N...

  • Netty源码分析3 - FastThreadLocal 框架的

    在 第二章 ThreadLocal源码解析 详细分析了jdk本身的ThreadLocal源码。本节来看一下nett...

  • ThreadLocal原理解析(2):ThreadLocalMa

    我的CSDN博客同步发布:ThreadLocal原理解析(2):ThreadLocalMap源码解析 转载请注明出...

  • ThreadLocal源码解析

    一、使用场景 ThreadLocal用于不同线程获取各自数据,同一个线程也可根据不同的threadlocal对象获...

  • ThreadLocal源码解析

    ThreadLocal 1. ThreadLocal 是什么? 源码中解释到 ThreadLocal 就用于存储数...

  • ThreadLocal源码解析

    引言 ThreadLocal,线程变量,线程可以将本次线程内经常使用的变量存储到ThreadLocal中,方便本次...

  • threadLocal源码解析

    简单记录一些看threadLocal时遇到比较有意思的点。 ThreadLocalMap ThreadLocal的...

  • ThreadLocal源码解析

    概述 ThreadLocal,即线程本地变量,它为每一个使用该变量的线程提供独立的变量副本,每一个线程都可以独立地...

  • ThreadLocal源码解析

    ThreadLocal源码阅读记录,如有不妥,欢迎指出,共同学习,谢谢! 一、简单使用 ThreadLocal可以...

  • ThreadLocal源码解析

    1.概述 多线程并发时用于存储当前线程的本地变量副本。 2. ThreadLocal解析 set:用于存储当前线程...

网友评论

      本文标题:ThreadLocal源码解析

      本文链接:https://www.haomeiwen.com/subject/jaunbftx.html