ThreadLocal使用及源码分析


版权声明:本文为博主原创文章,欢迎大家转载!

转载请标明出处: http://blog.csdn.net/guiying712/article/details/79250212 ,本文出自:【张华洋的博客】


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的实现,这里才是关键。

猜你喜欢

转载自blog.csdn.net/guiying712/article/details/79250212