ThreadLocal
1、 ThreadLocal线程局部变量。 JDK 提供的 ThreadLocal 使每一个线程都有自己的局部变量。
2、 ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
3、 使用场景:
1) ThreadLocal 可以用来管理 Session,因为每个人的信息都是不一样的,所以就很适合用 ThreadLocal 来管理
2) 数据库连接,为每一个线程分配一个独立的资源,也适合用 ThreadLocal 来实现
3) 比如 Spring 的事务管理器
4、 ThreadLocal原理:在 ThreadLocal 类中有一个 static 声明的 Map,用于存储每一个线程的变量副本,Map 中元素的key为线程对象,而value对应线程的变量副本。
5、 Thread、ThreadLocal 和 ThreadLocalMap 之间的关系:
1) 一个 Thread 中只有一个 ThreadLocalMap
2) 一个 ThreadLocalMap 中可以有多个 ThreadLocal 对象
(也就是说:一个 Thread 可以依附有多个 ThreadLocal 对象)
3) 一个 ThreadLocal 对象对应一个 ThreadLocalMap 中的一个 Entry
6、 ThreadLocal 的子类 InheritableThreadLocal 可以实现信息共享
7、 ThreadLocal 造成内存溢出的原因:如果 ThreadLocal 没有被直接引用(外部强引用),在 GC(垃圾回收)时,由于 ThreadLocalMap 中的 key 是弱引用,所以一定就会被回收,这样一来 ThreadLocalMap 中就会出现 key 为 null 的 Entry,并且没有办法访问这些数据,如果当前线程再迟迟不结束的话,这些 key 为 null 的 Entry 的 value 就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value 并且永远无法回收,从而造成内存泄漏。
import java.util.ArrayList;
import java.util.List;
public class ThreadLocalTest {
public static ThreadLocal<List<String>> threadLocal = new ThreadLocal<>();
public void getThreadLocal() {
System.out.println(Thread.currentThread().getName());
threadLocal.get().forEach(name -> System.out.println(name));
}
public void setThreadLocal(List<String> values) {
threadLocal.set(values);
}
public static void main(String[] args) {
final ThreadLocalTest threadLocalTest = new ThreadLocalTest();
new Thread(()->{
List<String> param = new ArrayList<>(3);
param.add("123");
param.add("456");
param.add("789");
threadLocalTest.setThreadLocal(param);
threadLocalTest.getThreadLocal();
}).start();
new Thread(()->{
List<String> param = new ArrayList<>(2);
param.add("elfkdfj");
param.add("djkfjcx");
threadLocalTest.setThreadLocal(param);
threadLocalTest.getThreadLocal();
}).start();
}
}
ThreadLocal 与 Synchronized 同步机制的比较
1、ThreadLocal 是线程局部变量,是一种多线程间并发访问变量的解决方案。和 Synchronized 等加锁的方式不同,ThreadLocal 完全不提供锁,而使用以空间换时间的方式,为每个线程提供变量的独立副本,以保证线程的安全。
2、在多线程并发情况下如何保证数据的安全性和一致性的两种主要方法:一种是加锁,另一种是使用 ThreadLocal。
3、锁是一种以时间换空间的方式,而 ThreadLocal 是一种以空间换时间的方式。