type
Post
status
Published
date
Feb 6, 2025
slug
ThreadLocal
summary
ThreadLocal 是 Java 中所提供的线程本地存储机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意方法中获取缓存的数据。
tags
线程
category
技术分享
icon
fa-solid fa-file
password
ThreadLocal 底层实现
ThreadLocal 是 Java 中所提供的线程本地存储机制,可以利用该机制将数据 缓存在某个线程内部 ,该线程可以在任意时刻、任意方法中获取缓存的数据。
ThreadLocal 底层是通过 ThreadLocalMap 来实现的,每个 Thread 对象中都存在一个 ThreadLocalMap 变量,这个 Map 的 key 就是我们要操作的 ThreadLocal 对象,Map 的 value 为需要缓存的值。我们在使用
ThreadLocal 的时候其实就是拿到当前线程中的 ThreadLocalMap 中的 key 和 value,ThreadLocal 本身不过是个工具类罢了。注意事项
如果在线程池中使用
ThreadLocal 可能会造成内存泄漏,因为当 ThreadLocal 对象使用完之后,应该要把设置的 key 和 value——也就是 Entry 对象进行回收。但线程池中的线程不会回收,并且 Thread 对象是通过强引用指向 ThreadLocalMap,ThreadLocalMap 也是通过强引用指向 Entry 对象,线程不被回收,Entry 对象也就不会被回收,从而导致不再使用的 Entry 对象越来越多,出现内存泄漏。解决办法是,在使用了
ThreadLocal 对象之后,手动调用 ThreadLocal 的 remove() 方法,手动清除 Entry 对象。
实线箭头是强引用,虚线箭头是弱引用
^4efc86
总结:当你在一个方法/栈中创建
ThreadLocal,该对象就被栈强引用着,直到方法执行完毕,栈被销毁,失去了强引用的、只有 ThreadLocalMap.Entry 弱引用的 ThreadLocal 就会被 GC 回收,但 ThreadLocalMap.Entry 中的 value 却实打实强引用了一个对象,entry 不死它就不死,所以说养成良好习惯 new ThreadLocal() 和 ThreadLocal.remove() 要在方法中成对出现。应用场景
当一个变量是共享的(成员变量、static 等),但是需要每个线程互不影响,相互隔离,就可以使用 ThreadLocal。
- 跨层传递信息的时候,每个方法都声明一个参数很麻烦,A、B、C、D 4 个类互相传递,每个方法都声明参数降低了维护性,可以用一个 ThreadLocal 共享变量,在 A 存值, B、C、D 都可以获取。
- 隔离线程,存储一些线程不安全的工具对象,如(SimpleDateFormat)。
- Spring 中的事务管理器就是使用的 ThreadLocal,这也是为什么声明式事务如果用到了多线程,它是没有办法达到一致性的,因为一个线程就存储了一个事务。
- SpringMVC 的 HttpSession、HttpServletReuqest、HttpServletResponse 都是放在 ThreadLocal,因为 servlet 是单例的,而 SpringMVC 允许在 controller 类中通过@Autowired 配置 request、response 以及 requestcontexts 等实例对象,在任何地方获取请求都永远是当前的请求。底层就是搭配 ThreadLocal 才实现线程安全。
- 作者:林明菁
- 链接:https://blog.lxuan.fun/article/ThreadLocal
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章






