为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个 Thread ,而是 Thread 的局部变量。
查看Thread 源码可得知:
/* 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;
ThreadLocal 原理:每个线程的内部都维护了一个 ThreadLocalMap,它是一个 Map(key,value)数据格式,key 是一个弱引用,也就是 ThreadLocal 本身,而 value 存的是线程变量的值。
直接运行一段代码
/**
* 36ThreadLocal 使用及实现原理
*
Thread-0 1
Thread-1 1
Thread-2 1
Thread-0 2
Thread-1 2
Thread-2 2
Thread-1 3
Thread-0 3
Thread-2 3
* @author Administrator
*/
public class Demo38ThreadLocal {
private ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return new Integer(0);
}
};
public int getNext() {
Integer value = count.get();
value++;
count.set(value);
return value;
}
public static void main(String[] args) {
Demo38ThreadLocal demo = new Demo38ThreadLocal();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() +" "+demo.getNext());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() +" "+ demo.getNext());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() +" "+ demo.getNext());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
线程资源持有
线程独立资源持有是threadlocal最常用的使用方式,比如从单线程应用扩展到多线程应用。
线程资源一致性
Entry数组的长度为啥一定要是2的幂
Hash 冲突
ThreadLocalMap 中解决 Hash 冲突的方式并非链表的方式,而是采用线性探测的方式.
所谓线性探测,就是根据初始 key 的 hashcode 值确定元素在 table 数组中的位置,如果发现这个位置上已经被其他的 key 值占用,则利用固定的算法寻找一定步长的下个位置,依次判断,直至找到能够存放的位置。
ThreadLocal特性
ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是
- Synchronized是通过线程等待,牺牲时间来解决访问冲突
- ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
内存泄漏
ThreadLocal 应用场景
- 线程间数据隔离,各线程的 ThreadLocal 互不影响
- 方便同一个线程使用某一对象,避免不必要的参数传递
- 全链路追踪中的 traceId 或者流程引擎中上下文的传递一般采用 ThreadLocal
- Spring 事务管理器采用了 ThreadLocal
- Spring MVC 的 RequestContextHolder 的实现使用了 ThreadLocal