本篇文章主要讲述ThreadLocal是如何实现线程本地变量的。<br />参考:冰河-高并发笔记<br /> CodeSheep-[https://mp.weixin.qq.com/s/ND-nUCGvXTHkEClKqN1qrQ](https://mp.weixin.qq.com/s/ND-nUCGvXTHkEClKqN1qrQ)
概述
解决线程安全问题的方法主要有阻塞同步、非阻塞同步和无同步方法(深入理解JVM 3版)
- 阻塞同步:synchronized和ReentrantLock
- 非阻塞同步:CAS
- 无同步方法:使用ThreadLocal
ThreadLocal将变量私有化,于是线程间没有共享数据,就不存在什么线程安全问题了
ThreadLocal原理探究
- 线程独享的变量存储在哪里?
- ThreadLocal的set()、get()、remove()方法的源码
- 如何让子线程获取父线程中设置的值
线程独享变量存储在哪里?
答:变量存储在该线程的Thread类实例中。
public class Thread implements Runnable {// 省略代码..../* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;// 省略代码....}
- ThreadLocal可以看成一个工具类
- 具体的作用就是操作当前线程的私有变量
ThreadLocal的方法源码分析
set()方法
```java public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null)
elsemap.set(this, value);
}createMap(t, value);
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}
- 当前线程调用 `ThreadLocal.set(xxx)`- `set()`方法获取当前是哪个线程调用的(这里调用线程假设为A)- 从线程A中获取它的`ThreadLocal.ThreadLocalMap threadLocals`的值- 为空,调用`createMap()` 为线程A创建一个- 不为空,修改原`threadLocals`成员变量的值<a name="XQGlJ"></a>### get()方法```javapublic T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;}
- 线程A调用
ThreadLocal.get()方法 - 获取当前调用线程(这里线程为线程A)
- 从线程A中获取
threadLocals成员变量 - 若
threadLocals不为空且threadLocals(可以看作一个Map)的里面值也不为空,则从中获取值 否则就是初始化这个
threadLocals并设置一个this->null键值对remove()方法
public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}
线程A调用
ThreadLocal.remove()- 获取当前调用线程(线程A)的
threadLocals -
子线程获取父线程的值
通过
ThreadLocal设置的值是不具备传递效果的,但是可以使用其子类InheritableThreadLocal来实现值的传递。InheritableThreadLocal的原理探究
父线程在
new Thread之前通过InheritableThreadLocal.set()设置值可以被新new出来的这个线程所拿到,并复制到新线程中public class Thread implements Runnable {// 省略代码..../* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;/** InheritableThreadLocal values pertaining to this thread. This map is* maintained by the InheritableThreadLocal class.*/ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;// 省略代码....}
在Thread中还有一个和
threadLocals类型一致的成员变量inheritableThreadLocals- 通过
ThreadLocal设置的线程变量存储在threadLocals中 通过
InheritableThreadLocal设置的线程变量存储在InheritableThreadLocals中方法探究
这里我就不列举
InheritableThreadLocal的set()、get()和remove()方法的具体代码了。
该类是ThreadLocal的子类,上述的三个方法均是ThreadLocal类的实现,唯一不同的是InheritableThreadLocal重写了其中获取调用线程中的ThreadLocal.ThreadMap的方法。ThreadLocal获取且操作threadLocalsInheritableThreadLocal则是操作inheritableThreadLocals如何传递
本质:将父线程的
inheritableThreadLocals成员变量赋值给子线程的inheritableThreadLocals- 发生位置:
new Thread()的构造方法执行过程中完成注意
作者认为,在new完子线程后,父线程对inheritableThreadLocals变量的修改失不会影响子线程的
ThreadLocal内存泄漏
待补充
