输出结果如下
线程名字:main---这是在主线程中线程名字:线程b---这是在线程b中线程名字:线程a---这是在线程a中线程名字:线程c---这是在线程c中Process finished with exit code 0
可以看出每个线程各通过ThreadLocal对自己ThreadLocalMap中的数据存取并没有出现脏读的现象 。就是因为每个线程内部已经存储了ThreadLocal为Key变量副本为Vaule的键值对 。(隔离了)
可能你有点懵 , ThreadLocal是怎么把变量复制到Thread的ThreadLocalMap中的?
咱们接着唠...
当我们初始化一个线程的时候其内部干去创建了一个ThreadLocalMap的Map容器待用 。
public class Thread implements Runnable { /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;}
当ThreadLocalMap被创建加载的时候其静态内部类Entry也随之加载 , 完成初始化动作 。
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }}
到此 , 线程Thread内部的Map容器初始化完毕 , 那么它又是如何和ThreadLocal产生关系 , ThreadLocal又是如何管理键值对的关系 。
【ThreadLocal源码探析】
ThreadLocal探析我们就其核心方法分析一下内部的逻辑 , 同时解答上述存在的疑问:
- set()方法用于保存当前线程的副本变量值 。
- get()方法用于获取当前线程的副本变量值 。
- initialValue()为当前线程初始副本变量值 。
- remove()方法移除当前线程的副本变量值 。
/** * 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 getMap(Thread t) { return t.threadLocals;}void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}
解说一下你就懂了:当我们在Thread内部调用set方法时:
- 第一步会去获取调用当前方法的线程Thread 。
- 然后顺其自然的拿到当前线程内部的ThreadLocalMap容器 。
- 最后就把变量副本给丢进去 。
get方法
/** * 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();}ThreadLocalMap getMap(Thread t) { return t.threadLocals;}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;}protected T initialValue() { return null;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 阿里的垃圾怎么回收?Java G1源码分析与调优手册
- Spring 源码第一篇开整!配置文件是怎么加载的?
- Redis如何清除过期key? 一篇文章带你走近源码!
- 花茶未来市场探析,花茶的感官鉴赏
- Window环境下编译Flink1.10源码
- Java自动化办公OA管理系统源码
- 从源码层,拆解OracleJDK和OpenJDK有什么区别?
- Linux 安装mysql5.7.29源码安装
- redis各类型数据结构和底层实现源码分析
- 中国茶叶之品牌及渠道构建密码探析