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

永远无法回收,造成内存泄漏。

 

posted on   潮流教父孙笑川  阅读(67)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示