从头认识多线程-4.4 ThreadLocal的实现原理
来源:互联网 发布:sqlserver清空数据库 编辑:程序博客网 时间:2024/06/11 02:37
从头认识多线程-4.4 ThreadLocal的实现原理
这一章节我们来讨论一下ThreadLocal的实现原理。
1.ThreadLocal的存储
一般可以认为是ThreadLocalMap这个内部类来存储,但是如果更加深入一层,其实他的存储是Entry类的可变数组,这个跟HashMap的存储比较相似
2.为什么在使用ThreadLocal的时候需要初始化?
ThreadLocal的初始化源码:
/** * Returns the current thread's "initial value" for this * thread-local variable. This method will be invoked the first * time a thread accesses the variable with the {@link #get} * method, unless the thread previously invoked the {@link #set} * method, in which case the <tt>initialValue</tt> method will not * be invoked for the thread. Normally, this method is invoked at * most once per thread, but it may be invoked again in case of * subsequent invocations of {@link #remove} followed by {@link #get}. * * <p>This implementation simply returns <tt>null</tt>; if the * programmer desires thread-local variables to have an initial * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * @return the initial value for this thread-local */ protected T initialValue() { return null; }
其实我们一打开源码就不难看见,其实在初始化之初,直接就是返回null,所以在没有初始化的情况下,直接get里面的元素,是返回null
3.set方法的实现
源码:
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
从源码看来,他使用了ThreadLocalMap作为容器,然后把值放到里面去,我们在进入ThreadLocalMap去看看
ThreadLocalMap是在ThreadLocal里面实现的内部类,由于代码太长这里就不贴出来,笔者曾看到有文章说ThreadLocalMap跟HashMap的实现是一样,然后仔细对比ThreadLocalMap跟HashMap的实现,是非常的相似,都是使用Entry数组来实现存储,然后遍历里面的元素,估计当时设计的思路都差不多,但是HashMap在Entry的实现上,明显比ThreadLocalMap的Entry要强。
4.get方法的实现,下面将解释为什么没有初始化,返回null
源码:
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
讲到get方法,我们深入debug,发现:
我们点击进去setInitialValue方法,
/** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
可以看到他返回的是value,而value,也就是初始化方法initialValue()的返回值,这里就解释了为什么没有初始化的时候,get返回的是null
5.为什么多线程情况下,每一个线程只会计算自己工作内存里面的变量副本?
我们分别看看set和get方法里面的某一两句
set方法
Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);
get方法
Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);
getMap方法
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
在两个方法里面,一开始都会出现这两句代码,这里我们点击去getmap方法,看见,里面出现了t.threadLocals,使用变量副本的原因就在这一句里面。
6.remove方法
源码:
/** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * <tt>initialValue</tt> method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
remove方法主要是去掉某个线程的变量副本,使得这个线程不能够在使用变量副本进行计算。
总结:我们这一章节简单的描述了ThreadLocal的实现原理。
这一章节就到这里,谢谢。
我的github:https://github.com/raylee2015/DeepIntoThread
目录:http://blog.csdn.net/raylee2007/article/details/51204573
- 从头认识多线程-4.4 ThreadLocal的实现原理
- 从头认识多线程-4.2 对象逸出的其他解决方案-主要是ThreadLocal的应用
- 从头认识多线程-4.3 ThreadLocal使用时需要注意的地方
- 从头认识多线程-1.1 多线程的创建
- 【Java多线程】ThreadLocal实现原理
- 从头认识多线程-2.5 锁的可重入性
- 从头认识多线程-目录
- 从头认识多线程-目录
- ThreadLocal的实现原理
- ThreadLocal的实现原理
- 认识ThreadLocal,多线程处理
- ThreadLocal,实现安全的多线程
- 从头认识java-17.1 多线程
- 从头认识多线程-1.3 currentThread()
- 从头认识多线程-1.14 优先级
- 源码|ThreadLocal的实现原理
- 从头认识多线程-1.16 对比不同的优先级
- 从头认识多线程-2.8 同步方法的隐患
- JavaSE入门学习46:文件传输基础之I/O流(五)(Java序列化)
- JavaSE入门学习45:文件传输基础之I/O流(四)
- 1-2新朋友你在哪里(如何插入JS)
- 轮播器
- JavaSE入门学习44:文件传输基础之I/O流(三)
- 从头认识多线程-4.4 ThreadLocal的实现原理
- 小玩文件(2)
- getopt函数
- [linux]using temporary as lvalue [-fpermissive]
- 酷炫的Activity切换动画,打造更好的用户体验
- 由GroupBy-Having想到的
- mongodb安装与配置
- JavaSE入门学习43:文件传输基础之I/O流(二)
- Git超简明教程