Thread、ThreadLocal、ThreadLocalMap
参考:
Java并发常见面试题总结(下) | JavaGuide
ThreadLocal 详解 | JavaGuide
通常情况下,我们创建的变量可以被任何一个线程访问和修改。这在多线程环境中可能导致数据竞争和线程安全问题。那么,如果想让每个线程都有自己的专属本地变量,该如何实现呢?
JDK 中提供的
ThreadLocal
类正是为了解决这个问题。ThreadLocal
类允许每个线程绑定自己的值。
ThreadLocalMap
每个Thread对象内部都有一个成员变量 ThreadLocalMap。
ThreadLocalMap是一个定制哈希表,定义在ThreadLocal内部,key是ThreadLocal的实例(弱引用),value是set进去的值(强引用)。
ThreadLocal
ThreadLocal相当于一个工具类,对外暴露get、set、remove方法,在内部再通过currentThread拿到当前线程的ThreadLocalMap,再操作这个 map。
存储结构示例:
Thread t1
├── threadLocals (ThreadLocalMap)
│ ├── Entry[0]: key=ThreadLocal@A(弱引用), value=UserObj@X
│ ├── Entry[1]: key=ThreadLocal@B(弱引用), value=UserObj@Y
│ └── ...
ThreadLocal缺点
-
内存泄漏
-
柜子钥匙(ThreadLocal 对象)是弱引用,容易被垃圾回收。
-
但柜子里面的value 是强引用,如果线程一直不死(如线程池复用),value 就永远占着内存 。
-
解决:用完一定要
finally { threadLocal.remove(); }
。
-
-
脏读
-
线程池把同一条线程反复租给不同任务,上一次任务留下的 value 被下一次任务“误拿”,出现数据串味 。
-
解决:同上,任务开始前先
remove()
。
-
-
不可继承
-
主线程的 ThreadLocal 值,子线程默认看不见(父子线程不同柜子)。
-
若需要传递,用
InheritableThreadLocal
,但也只能传创建子线程那一刻的“快照” 。
-