ThreadLocal ,使用场景,内存泄漏问题。更正对threadlocal的理解。SimpleDateFormat中使用了threadlocalMap
set方法
public void set(T value) { Thread t = Thread.currentThread(); //获取当前线程 ThreadLocalMap map = getMap(t); //获取当前线程的threadlocalmap,不是threadlocal的,threadlocal只是一个中介,为了获取线程的threadlocalMap if (map != null) map.set(this, value); else createMap(t, value); }
key就是this,指当前的threadlocal。实质上是在当前的thread中取出threadlocalMap,然后key是threadlocal
value就弱引用
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
WeakReference,当主对象被回收后,还有ThreadLocalMap关联着value对象,如果
ThreadLocalMap 一直不被回收,那么value也不会被回收,容易发生内存泄漏问题,所以使用弱引用关联

2个对象关联着ENtry,一个是当前线程,一个是Threadlocal,当前线程使用完要remove掉,才能保证弱引用的Entry能够被回收掉
是当前线程的threadLocalMap中,key是包含了threadlocal的
ThreadLocal
提供了线程独有的局部变量,可以在整个线程存活的过程中随时取用,极大地方便了一些逻辑的实现。常见的ThreadLocal用法有:
- 存储单个线程上下文信息。比如存储id等;
- 使变量线程安全。变量既然成为了每个线程内部的局部变量,自然就不会存在并发问题了;
- 减少参数传递。比如做一个trace工具,能够输出工程从开始到结束的整个一次处理过程中所有的信息,从而方便debug。由于需要在工程各处随时取用,可放入ThreadLocal。
用SimpleDateFormat这个对象,进行日期格式化。因为创建这个对象本身很费时的,而且我们也知道SimpleDateFormat本身不是线程安全的,也不能缓存一个共享的SimpleDateFormat实例,为此我们想到使用ThreadLocal来给每个线程缓存一个SimpleDateFormat实例,提高性能。同时因为每个Servlet会用到不同pattern的时间格式化类,所以我们对应每一种pattern生成了一个ThreadLocal实例。
public interface DateTimeFormat { String DATE_PATTERN = "yyyy-MM-dd"; ThreadLocal<DateFormat> DATE_FORMAT = ThreadLocal.withInitial(() -> { return new SimpleDateFormat("yyyy-MM-dd"); }); String TIME_PATTERN = "HH:mm:ss"; ThreadLocal<DateFormat> TIME_FORMAT = ThreadLocal.withInitial(() -> { return new SimpleDateFormat("HH:mm:ss"); }); String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; ThreadLocal<DateFormat> DATE_TIME_FORMAT = ThreadLocal.withInitial(() -> { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); }); }
ThreadLocal 内存泄漏的原因
从上图中可以看出,hreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有thead线程退出以后,value的强引用链条才会断掉。
但如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value
永远无法回收,造成内存泄漏。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)