### ThreadLocal
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景
ThreadLocal是为了隔离多个线程数据共享,从根本上就不存在多个线程之间共享资源;
**ThreadLocal的内部结构图**
![](https://img.kancloud.cn/53/85/53851a16ea31d175389d88b7df04306d_806x837.png)
**ThreadLocal的核心机制**
* 每个Thread线程内部都有一个Map
* Map里面存储线程本地对象(key)和线程的变量副本(value)
* Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值
**ThreadLocal类核心方法**
```
public T get()
public void set(T value)
public void remove()
```
* get\(\)方法用于获取当前线程的副本变量值;
* set\(\)方法用于保存当前线程的副本变量值;
* initialValue\(\)为当前线程初始副本变量值;
* remove\(\)方法移除当前前程的副本变量值;
**ThreadLocalMap**
ThreadLocalMap是ThreadLocal的内部类,没有实现Map接口,用独立的方式实现了Map的功能,其内部的Entry也独立实现
![](https://img.kancloud.cn/98/b7/98b7029ce12d46ed5d55403f6a8f6d86_576x330.png)
在ThreadLocalMap中,也是用Entry来保存K-V结构数据的。但是Entry中key只能是ThreadLocal对象,这点被Entry的构造方法已经限定死;Entry继承自WeakReference(弱引用,生命周期只能存活到下次GC前),但只有Key是弱引用类型的,Value并非弱引用
```
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
```
**Hash冲突**
和HashMap的最大的不同在于,ThreadLocalMap结构非常简单,没有next引用,也就是说ThreadLocalMap中解决Hash冲突的方式并非链表的方式,而是采用线性探测的方式,所谓线性探测,就是根据初始key的hashcode值确定元素在table数组中的位置,如果发现这个位置上已经有其他key值的元素被占用,则利用固定的算法寻找一定步长的下个位置,依次判断,直至找到能够存放的位置
ThreadLocalMap解决Hash冲突的方式就是简单的步长加1或减1,寻找下一个相邻的位置
```
/**
* Increment i modulo len.
*/
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
/**
* Decrement i modulo len.
*/
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
```
### 【知识点】
由于ThreadLocalMap的key是弱引用,而Value是强引用。这就导致了一个问题,ThreadLocal在没有外部对象强引用时,发生GC时弱引用Key会被回收,而Value不会回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露
如何避免泄漏
既然Key是弱引用,那么我们要做的事,就是在调用ThreadLocal的get\(\)、set\(\)方法时完成后再调用remove方法,将Entry节点和Map的引用关系移除,这样整个Entry对象在GC Roots分析后就变成不可达了,下次GC的时候就可以被回收
- 简介
- 概述
- 进程vs线程
- 资源限制
- 有关并行的两个定律
- 线程同步和阻塞
- 线程阻塞
- 线程的特性
- 守护线程
- 线程异常
- Thread
- 线程状态
- 线程中断
- wait¬ify
- suspend&resume
- join&yield
- notify¬ifyAll
- Thread.sleep
- 线程任务
- Runnable
- Callable
- Future模式
- FutureTask
- 线程实现方式
- 内核线程实现
- 用户线程实现
- 混合实现
- Java线程的实现
- java与协程
- 纤程-Fiber
- 线程调度
- 多线程协作方式
- 阻塞
- 放弃
- 休眠
- 连接线程
- 线程估算公式
- 线程活跃性
- 死锁
- 线程安全性
- 对象的发布与逸出
- 构造方法溢出
- 线程封闭
- 对象的可变性
- 原子性
- 原子操作
- CPU原子操作原理
- 总线锁
- 缓存锁
- JAVA如何实现原子操作
- long和double读写操作原子性
- Adder和Accumulator
- 线程性能
- 同步工具类
- 闭锁
- CountDownLatch
- FutureTask
- 信号量
- 栅栏
- CyclicBarrier
- Exchanger
- 并发编程
- volatile
- synchronized
- 无锁
- 偏向锁
- 轻量级锁
- 锁的优缺点对比
- 锁升级
- 锁消除
- Monitor
- synchronized语法
- Mutex Lock
- synchronized实践问题
- synchronized&ReentrantLock
- Lock
- ReentrantLock
- Condition
- 读写锁
- ReadWriteLock
- StampedLock
- 线程池
- Executor
- ExecutorService
- Executors
- ThreadPoolExecutor
- RejectedExecutionHandler
- ThreadFactory
- 线程池大小公式
- 动态调整线程池大小
- Fork/Join框架
- ForkJoinPool
- CompletableFuture
- JUC并发工具包
- LockSupport
- 延时任务与周期任务
- Timer
- TimerTask
- 异构任务并行化
- CompletionService
- volatile和synchronized比较
- 锁优化
- 锁相关概念
- 悲观锁(排它锁)
- 乐观锁
- 自旋锁
- 乐观锁vs悲观锁
- JVM锁优化-锁消除
- ThreadLocal
- InheritableThreadLocal
- TransmittableThreadLocal
- ThreadLocalRandom
- 无锁
- AtomicInteger
- Unsafe
- AtomicReference
- AtomicStampedReference
- AtomicIntegerArray
- AtomicIntegerFieldUpdater
- 无锁Vector
- LongAdder
- LongAccumulator
- 常见锁类型
- 悲观锁&独占锁
- 乐观锁
- 乐观锁vs悲观锁
- 自旋锁vs适应性自旋锁
- 公平锁vs非公平锁
- 可重入锁vs非可重入锁
- 独享锁vs共享锁
- 互斥锁
- CAS
- AQS介绍
- AQS深入剖析
- AQS框架
- AQS核心思想
- AQS数据结构
- 同步状态State
- ReentrantLock vs AQS
- AQS与ReentrantLock的关联
- ReentrantLock具体实现
- 线程加入等待队列
- 等待队列中线程出队列时机
- 如何解锁
- 中断恢复后的执行流程
- ReentrantLock的可重入应用
- JUC中的应用场景
- 自定义同步工具
- CLH锁
- 并发框架
- Akka
- Disruptor-无锁缓存框架
- 常见面试题
- 两个线程交替打印A和B
- 附录