• 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日,下午。 

  • 相关阅读:
    第十一章 表单与验证
    第十章 日期与时间
    第九章 正则表达式
    第八章 字符串处理
    纯C实现面向对象之接口编程
    csharp 面向对象编程
    cpp面向对象编程
    javascriptMVC框架面向对象编程
    堆栈的区别
    Java堆栈简介
  • 原文地址:https://www.cnblogs.com/developer_chan/p/9125716.html
Copyright © 2020-2023  润新知