继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

ThreadLocal使用及源码分析

喵喵一只汪
关注TA
已关注
手记 315
粉丝 87
获赞 467

ThreadLocal 提供了线程本地变量。这些变量不同于普通变量,每个线程都可以通过 ThreadLocal 的 get 或 set 方法访问这个线程自己的变量,独立初始化变量的副本。ThreadLocal 实例通常在其他类中是  private static 域,它希望将自己的状态与一个线程关联起来。

说的通俗点就是:如果我们想要让一个变量在每一个线程中都拥有独立的值,就需要用到ThreadLocal。

验证线程变量的隔离性

我们先写一段 Android 测试代码:

public class ThreadTestActivity extends AppCompatActivity {
    private static final String TAG = "ThreadTestActivity ";    private static ThreadLocal<String> mStringThreadLocal = new ThreadLocal<>();    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_acc);

        mStringThreadLocal.set("[Thread#main]");
        Log.e(TAG, "[Thread#main] ThreadLocal String =" + mStringThreadLocal.get());        new Thread("Thread#1") {            @Override
            public void run() {
                mStringThreadLocal.set("[Thread#1]");
                Log.d(TAG, "[Thread#1] ThreadLocal String =" + mStringThreadLocal.get());
            }
        }.start();        new Thread("Thread#2") {            @Override
            public void run() {
                Log.w(TAG, "[Thread#2] ThreadLocal String =" + mStringThreadLocal.get());
            }
        }.start();
    }
}

程序运行的结果如下图所示:

这里写图片描述

从图中的运行结果来看,第一次在主线程中调用成员变量 mStringThreadLocalset 方法保存了“[Thread#main]”,所以在主线程中调用  get方法 时返回的值是  “[Thread#main]”

然后我们在子线程Thread#1中保存了“[Thread#1]”,调用 get方法 时返回的值是  “[Thread#1]”

最后我们在子线程Thread#2中没有保存任何内容,直接调用 get方法 时返回的值是  null

类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程中的值 是可以放入 ThreadLocal 中进行保存的。

ThreadLocal 源码解析

那么ThreadLocal 是如何做到的呢?我们先看下ThreadLocal 的set()方法:

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);        //如果当前线程的ThreadLocalMap为空,就new一个Map,否则以当前ThreadLocal对象为key值,存入线程的Map中
        if (map != null)
            map.set(this, value);        else
            createMap(t, value);
    }

在 set() 方法中,首先拿到了当前所在线程,就是我们调用ThreadLocal 的 set() 方法时所在的线程,然后执行了 getMap() 方法:

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

getMap()方法返回了当前线程所持有的ThreadLocalMap,我们进入 Thread 类中,CTRL+F 搜索 threadLocals,可以找到 Threadd 的成员变量 threadLocals

 ThreadLocal.ThreadLocalMap threadLocals = null;

也就是说,每一个 Thread 类中都持有一个ThreadLocal.ThreadLocalMap。而我们需要保存的变量值就是保存在这个线程的 ThreadLocalMap 中的。

ThreadLocal的代码总体比较简单,没有什么可讲的,我们直接进入ThreadLocal中的嵌套内部类ThreadLocalMap的实现,这里才是关键。

原文出处


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP