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 2020-10-23 17:55  潮流教父孙笑川  阅读(80)  评论(0)    收藏  举报

导航