ThreadLocal总体介绍
ThreadLocal类在并发编程中,每个线程实例,都有一份独立的副本,采用以空间换时间的方式,处理并发。
在Thread类中,ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap就是线程变量的容器。
1 | static class ThreadLocalMap { |
如上代码可以看到Entry继承了WeakReference,在构造函数中super(key)
,key就是指ThreadLocal引用本身this。跟WeakHashMap不同的是,ThreadLocal的构造函数,没有指定ReferenceQueue。ThreadLocal用一种不同的方式,来避免内存泄漏,在下面的章节中,会详细介绍ThreadLocal的方式。
ThreadLocal的API,就不在此阐述,很简单。
每个线程独立备份
为了达到这个目的,有两个方案。
## 方案A
ThreadLocal 维护一个 Map,键是 Thread,值是它在该 Thread 内的实例。增加线程与减少线程均需要写 Map,故需保证该 Map 线程安全。线程结束时,需要保证它所访问的所有 ThreadLocal 中对应的映射均删除,否则可能会引起内存泄漏。
- 结论:加锁势必会降低ThreadLocal的性能。猜测JDK为了性能考虑,没有采用此方案。
方案B
Map 由 Thread 维护,从而使得每个 Thread 只访问自己的 Map,那就不存在多线程写的问题,也就不需要锁。该方案虽然没有锁的问题,但是由于每个线程访问某 ThreadLocal 变量后,都会在自己的 Map 内维护该 ThreadLocal 变量与具体实例的映射,如果不删除这些引用(映射),则这些 ThreadLocal 不能被回收,可能会造成内存泄漏。
- 结论:JDK采用了B方案,也有对应的方案来解决内存泄漏问题。
#JDK如何解决内存泄漏问题