ThreadLocal源码学习

ThreadLocal,线程本地化对象,在多线程环境中,使用ThreadLocal对象来维护变量时,ThreadLocal为每个使用该变量的线程维护一个独立的线程副本。

ThreadLocal.java源文件内容为:

  1 /**
  2   * ThreadLocal内部包含一个用数组实现的哈希表,用来存储对应到每个线程的局部对象的值
  3   * 其中,ThreadLocal对象担当key,实际通过threadLocalHashCode值来进行检索
  4   */
  5 public class ThreadLocal<T> {
  6     //其中 T 类型代表的是被多个线程访问的局部变量类型
 10     private final int threadLocalHashCode = nextHashCode();
 11     /**
 12     * Returns the current thread‘s "initial value" for this
 13     * thread-local variable. This method will be invoked the first
 14     * time a thread accesses the variable with the {@link #get}
 15     * method, unless the thread previously invoked the {@link #set}
 16     * method, in which case the <tt>initialValue</tt> method will not
 17     * be invoked for the thread. Normally, this method is invoked at
 18     * most once per thread, but it may be invoked again in case of
 19     * subsequent invocations of {@link #remove} followed by {@link #get}.
 20     * * <p>This implementation simply returns <tt>null</tt>; if the
 21     * programmer desires thread-local variables to have an initial
 22     * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
 23     * subclassed, and this method overridden. Typically, an
 24     * anonymous inner class will be used.
 25     * * @return the initial value for this thread-local(返回当前线程局部对象的初始值)
 26     */
 27     protected T initialValue() {
 28         //protected成员,期望被子类继承
 29         return null;
 30     }
 31     /**
 32     * 返回在当前线程中的线程局部对象的值,
 33     * 若线程局部对象对于当前线程没有值,则被初始化微 initialValue方法的返回值
 34     */
 35     public T get() {
 36         Thread t = Thread.currentThread();
 37         ThreadLocalMap map = getMap(t);
 38         if (map != null) {
 39             ThreadLocalMap.Entry e = map.getEntry(this);
 40             if (e != null)
 41                 return (T)e.value;
 42         }
 43
 44             return setInitialValue();
 45     }
 46
 47     /**
 48     * Sets the current thread‘s copy of this thread-local variable
 49     * to the specified value. Most subclasses will have no need to
 50     * override this method, relying solely on the method to set the values of thread-locals.
 51     */
 52     public void set(T value) {
 53         Thread t = Thread.currentThread();
 54         ThreadLocalMap map = getMap(t);
 55         if (map != null)
 56             //以当前线程对象为key,设置当前局部对象的值
 57             map.set(this, value);
 58         else
 59             createMap(t, value);
 60     }
 61
 62     /**
 63     * Removes the current thread‘s value for this thread-local
 64     * variable. If this thread-local variable is subsequently
 65     * {@linkplain #get read} by the current thread, its value will be
 66     * reinitialized by invoking its {@link #initialValue} method,
 67     * unless its value is {@linkplain #set set} by the current thread
 68     * in the interim. This may result in multiple invocations of the
 69     * <tt>initialValue</tt> method in the current thread.
 70     */
 71     public void remove() {
 72         ThreadLocalMap m = getMap(Thread.currentThread());
 73         if (m != null)
 74             //从ThreadLocalMap中移除对象
 75             m.remove(this);
 76     }
 77
 78     /**
 79     * Get the map associated with a ThreadLocal. Overridden in
 80     * InheritableThreadLocal.
 81     * * @param t the current thread
 82     * @return the map
 83     */
 84     ThreadLocalMap getMap(Thread t) {
 85         //返回当前Threadlocal相关的ThreadLocalMap对象
 86         return t.threadLocals;
 87     }
 88
 89     /**
 90     * Create the map associated with a ThreadLocal. Overridden in
 91     * InheritableThreadLocal.
 92     * * @param t the current thread
 93     * @param firstValue value for the initial entry of the map
 94     * @param map the map to store.
 95     */
 96     void createMap(Thread t, T firstValue) {
 97         t.threadLocals = new ThreadLocalMap(this, firstValue); //为当前线程创建关联的ThreadLocalMap对象
 98     }
 99
100     //ThreadLocalMap是一个定制的只能用来存储线程局部对象的哈希映射
101     //使用弱引用来当做key,只有当表空间不够时,旧的对象才会被移除
102     static class ThreadLocalMap {
103         //ThreadLocalMap的内部数组的元素类型:使用对ThreadLocal的弱引用类型来作为元素类型
104         static class Entry extends WeakReference<ThreadLocal> {
105         /**
106         * The value associated with this ThreadLocal.
107         */
108         Object value;
109
110         Entry(ThreadLocal k, Object v) {
111             super(k);
112             value = v;
113         }
114     }
115
116     //哈希表的初始大小
117     private static final int INITIAL_CAPACITY = 16;
118
119     /**
120     * 用于存储ThreadLocal弱引用的数组
121     */
122     private Entry[] table;
123
124     //ThreadLocalMap使用延迟初始化,当我们需要向ThreadLocalMap中放元素时,才会初始化它
125     ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
126         table = new Entry[INITIAL_CAPACITY];
127         int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
128         table[i] = new Entry(firstKey, firstValue); //初始时,使用ThreadLocal.threadLocalHashCode作为哈希表的哈希值 size = 1;
129
130         //设定ThreadLocalMap中元素个数
131         setThreshold(INITIAL_CAPACITY);
132     }
133
134     /**
135     * Set the value associated with key.
136     * * @param key the thread local object
137     * @param value the value to be set
138     */
139     private void set(ThreadLocal key, Object value) {
140         // We don‘t use a fast path as with get() because it is at
141         // least as common to use set() to create new entries as
142         // it is to replace existing ones, in which case, a fast
143         // path would fail more often than not.
144         Entry[] tab = table;
145         int len = tab.length;
146         int i = key.threadLocalHashCode & (len-1);
147         for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
148             ThreadLocal k = e.get();
149             if (k == key) {
150                 e.value = value;
151                 return;
152             }
153
154             if (k == null) {
155                 replaceStaleEntry(key, value, i);
156                 return;
157             }
158         }
159
160         tab[i] = new Entry(key, value);
161         int sz = ++size;
162         if (!cleanSomeSlots(i, sz) && sz >= threshold)
163             rehash();
164     }
165
166     /**
167     * Remove the entry for key.
168     */
169     private void remove(ThreadLocal key) {
170         Entry[] tab = table;
171         int len = tab.length;
172         int i = key.threadLocalHashCode & (len-1);
173         for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
174             if (e.get() == key) {
175                 e.clear();
176                 expungeStaleEntry(i);
177                 return;
178             }
179         }
180     }
181 }

ThreadLocal源码学习,布布扣,bubuko.com

时间: 2024-10-01 02:49:09

ThreadLocal源码学习的相关文章

struts2源码学习之初始化(三)

在上一篇struts2源码学习之初始化(二)中已经详细介绍了Dispatcher的初始化工作,只差最后一点,容器的创建.这一篇就仔细介绍容器的创建过程,初始化过程以及容器的作用.还是先从源码入手,上一篇已经分析到了Dispatcher类的init()的这段代码: Container container = init_PreloadConfiguration(); container.inject(this); init_CheckWebLogicWorkaround(container); 接着

Java多线程之JUC包:ReentrantReadWriteLock源码学习笔记

若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/go2sea/p/5634701.html ReentrantLock提供了标准的互斥操作,但在应用中,我们对一个资源的访问有两种方式:读和写,读操作一般不会影响数据的一致性问题.但如果我们使用ReentrantLock,则在需要在读操作的时候也独占锁,这会导致并发效率大大降低.JUC包提供了读写锁ReentrantReadWriteLock,使得读写锁分离,在上述情

Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设计精巧,代码优美,值得每一名开发人员学习阅读. 在我最开始学习javaEE时,第一次接触Spring是从一个S(Struts)S(Spring)H(Herbinate)的框架开始.由java原生开发到框架开发转换过程中,那时我的印象里Struts负责控制层,herbinate负责数据层,而Sprin

阿里架构师浅析ThreadLocal源码——黄金分割数的使用

一. 前提 最近接触到的一个项目要兼容新老系统,最终采用了ThreadLocal(实际上用的是InheritableThreadLocal)用于在子线程获取父线程中共享的变量.问题是解决了,但是后来发现对ThreadLocal的理解不够深入,于是顺便把它的源码阅读理解了一遍.在谈到ThreadLocal之前先买个关子,先谈谈黄金分割数.本文在阅读ThreadLocal源码的时候是使用JDK8(1.8.0_181). 二. 黄金分割数与斐波那契数列 首先复习一下斐波那契数列,下面的推导过程来自某搜

FireMonkey 源码学习(5)

(5)UpdateCharRec 该函数的源码分析如下: procedure TTextLayoutNG.UpdateCharRec(const ACanvas: TCanvas; NeedBitmap: Boolean; var NewRec: PCharRec; HasItem: Boolean; const CharDic: TCharDic; const AFont: TFont; const Ch: UCS4Char; const NeedPath: Boolean = False);

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修

Threadlocal源码分析以及其中WeakReference作用分析

今天在看Spring 3.x企业应用开发实战,第九章 Spring的事务管理,9.2.2节ThreadLocal的接口方法时,书上有提到Threadlocal的简单实现,我就去看了下JDK1.8的Threadlocal的源码.发现实现方式与书中讲的并不相同,同时在网上搜索了一下,发现有比较多的人理解错了. 先看一下容易误导的解释:在ThreadLocal类中有一个Map对象,这个Map以每个Thread对象为键,保存了这个线程对应局部变量值,对应的实现方式如下: public class Sim

Hadoop源码学习笔记(1) ——第二季开始——找到Main函数及读一读Configure类

Hadoop源码学习笔记(1) ——找到Main函数及读一读Configure类 前面在第一季中,我们简单地研究了下Hadoop是什么,怎么用.在这开源的大牛作品的诱惑下,接下来我们要研究一下它是如何实现的. 提前申明,本人是一直搞.net的,对java略为生疏,所以在学习该作品时,会时不时插入对java的学习,到时也会摆一些上来,包括一下设计模式之类的.欢迎高手指正. 整个学习过程,我们主要通过eclipse来学习,之前已经讲过如何在eclipse中搭建调试环境,这里就不多述了. 在之前源码初

HSQLDB源码学习——数据库安装启动及JDBC连接

HSQLDB 是一个轻量级的纯Java开发的开放源代码的关系数据库系统.因为HSQLDB的轻量(占用空间小),使用简单,支持内存运行方式等特点,HSQLDB被广泛用于开发环境和某些中小型系统中. 在http://sourceforge.net/projects/hsqldb/files/下载了HSQLDB 1.8.0版本.把下载的zip文件解压缩至任意目录例如c:\hsqldb1.8便完成安装. hsqldb有四种运行模式: 一.内存(Memory-Only)模式:所有数据都在内存里操作.应用程