ThreadLocal

介绍

线程本地变量,访问这个变量的每个线程都会有这个变量的一个本地拷贝,多个线程操作这个变量的时候,实际是在操作自己本地内存里面的变量,从而起到线程隔离的作用,避免了并发场景下的线程安全问题

 

 

public class ThreadLocalUse {
    private static final ThreadLocal<DateFormat> DATE_FORMAT_THREAD_LOCAL = new ThreadLocal<DateFormat>(){
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    };
    public static Date convert(String source) throws ParseException {
        return DATE_FORMAT_THREAD_LOCAL.get().parse(source);
    }
    /**
     * @description Removes the current thread's value for this thread-local variable.
     */
    public static void remove(){
        DATE_FORMAT_THREAD_LOCAL.remove();
    }
}

 

应用场景

日期工具类DateUtil中会用ThreadLocal来让每个线程装在自己的SimpleDateFormat对象

 

spring提供了事务相关的操作,一次事务的所有操作需要在同一个数据库连接上,但是不需要我们关注

spring就是用 ThreadLocal来实现的,ThreadLocal存储的类型是一个Map

Map中的key是DataSource,value是Connection(为了应对多数据源的情况,所以是一个Map)

用了ThreadLocal保证了同一个线程获取一个Connection对象,从而保证一次事务的所有操作需要在同一个数据库连接上

 

 

ThreadLocal原理

threadLocal真正存储数据的是内部类ThreadLocalMap,ThreadLocalMap的引用是在Thread上定义的

 

 

Thread类里面有两个变量 ,htreadLocals和inheritableThreadLocals,都是ThreadLocal.ThreadLocalMap类型的变量,当前线程调用ThreadLocal的set、get方法时创建

ThreadLocalMap的key是ThreadLocal,value是set的值,线程内创建多个ThreadLocal共用线程仅有的ThreadLocaLMap

 

 为什么不是Thread作为key?

一个线程可以拥有多个私有变量,key是当前线程的话,还需要用唯一标识来标识set进去的value

并发量大时,所有线程去操作同一个Map,Map体积可能会膨胀,导致访问的性能下降

该Map维护着所有线程的私有变量,意味着不知道什么时候可以销毁

threadLocal作为key,线程销毁了,ThreadLocal也会被销毁

 

ThreadLocal内存泄露

ThreadLocalMap 中使⽤的 key 为 ThreadLocal 的弱引⽤,⽽ value 是强引⽤。所以,如果ThreadLocal 没有被外部强引⽤的情况下,在垃圾

回收的时候,key 会被清理掉,⽽ value 不会被清理掉。这样⼀来, ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何

措施的话,value 永远⽆法被 GC 回收,这个时候就可能会产⽣内存泄露

ThreadLocalMap实现中已经考虑了这种情况,在调用set()、get(),remove方法的时候,会清理掉key为null的记录。使用完ThreadLocal方法

后,最好手动remove()一下。

 

概率非常低 ThreadLocal会被两种引用指向

1):ThreadLocalRef->ThreadLocal(强引⽤,被对应的栈引用关联,创建Thread时,栈引用-》Thread-》Thread内部维护了ThreadLocalMap的引用)

2):ThreadLocalMap Entry key ->ThreadLocal(弱引⽤)

只要ThreadLocal没有被回收,那ThreadLocalMap key的指向就不会再GC时 被断开,也就不会有内存泄露

 

posted on 2023-03-09 07:33  or追梦者  阅读(21)  评论(0编辑  收藏  举报