ThreadLocal源码调试——“this”作为key

Posted developer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal源码调试——“this”作为key相关的知识,希望对你有一定的参考价值。

前言:在一次面试过程中被问到ThreadLocal,大家都知道ThreadLocal可以为每个线程单独提供一个副本,从而实现变量间的隔离。在ThreadLocal中set和get操作的key是什么,ThreadLocal又是怎样实现各线程间互不干扰的,本文通过调试ThreadLocal的源码来阐述这些问题。

注:jdk版本:jdk1.7.0_51


1.set与get源码

1   public void set(T value) {
2         Thread t = Thread.currentThread();
3         ThreadLocalMap map = getMap(t);
4         if (map != null)
5             map.set(this, value);
6         else
7             createMap(t, value);
8     }
 1  public T get() {
 2         Thread t = Thread.currentThread();
 3         ThreadLocalMap map = getMap(t);
 4         if (map != null) {
 5             ThreadLocalMap.Entry e = map.getEntry(this);
 6             if (e != null)
 7                 return (T)e.value;
 8         }
 9         return setInitialValue();
10     }

下面通过对源码的调试说明具体流程。

2.具体调试过程

 1 public class CodeTest02
 2 {
 3     public static void main(String[] args) throws InterruptedException
 4     {
 5         final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
 6 
 7         Thread t1 = new Thread(new Runnable()
 8         {
 9             @Override
10             public void run()
11             {
12                 threadLocal.set(1);
13 
14                 System.out.println(threadLocal.get());
15             }
16         },"t1");
17         t1.start();
18 
19         t1.join();
20         threadLocal.set(2);
21 
22         System.out.println(threadLocal.get());
23 
24 
25     }
26 
27 }

说明:在主线程和t1线程中进行set操作,最后输出如下:

从输出结果可以看出两个线程间的值互不影响。

具体调试过程:

注意:当前threadLocal的地址值为ThreadLocal@430进入断点,如下图所示。

注意:

1)this的值为当前ThreadLocal对象的值(ThreadLocal@430)。

2)t表示当前线程t1。

3)map为空,注意这里的map为ThreadLocalMap。

转入createMap函数,传入的值为当前线程t1和value(value=1)。

说明:

1)createMap函数会为t1线程创建一个ThreadLocalMap。

从注释中可以看出,ThreadLocal为线程的附属值,所以ThreadLocalMap也为线程的一个附属属性,它被ThreadLocal维护。

2)该ThreadLocalMap的键为this,从调试信息中可以看出this的值为ThreadLocal@430。

接下来看get函数:

说明:

1)通过t1线程,取出ThreadLocalMap,这里获取set中根据t1创建的threadLocals对象。

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

2)在ThreadLocalMap中根据this,也就是当前ThreadLocal@430,取得设置的值。

总结:

1)ThreadLocal中在set操作时,key为当前ThreadLocal对象

2)ThreadLocal会为每个线程都创建一个ThreadLocalMap,对应程序中的t.threadLocals = new ThreadLocalMap(this, firstValue),ThreadLocalMap为当前线程的属性。

3)通过对每个线程创建一个ThreadLocalMap实现本地副本。当取值时,实际上就是通过key在map中取值,当然此时的key为ThreadLocal对象,而map为每个线程独有的map,从而实现变量的互不干扰。


by Shawn Chen,2018.6.2日,下午。 

以上是关于ThreadLocal源码调试——“this”作为key的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出Java并发编程指南「源码分析篇」透析ThreadLocal线程私有区域的运作机制和源码体系

原创源码角度分析Android的消息机制系列——ThreadLocal的工作过程

ThreadLocal理解

ThreadLocal源码解析-Java8

java多线程17:ThreadLocal源码剖析

Java多线程9:ThreadLocal源码剖析