ThreadLocal

ThreadLocal

线程封闭

对象封闭在一个线程中,即使这个对象不是线程安全的,也不会出现并发安全问题。

例如:栈封闭:就是用栈来保证线程安全。

public void test(){
	StringBuilder s = new StringBuilder();
	s.append("Hello");
}

StringBuilder是线程不安全的,但它只是个局部变量,局部变量存储在虚拟机栈,虚拟机栈是线程隔离的,所以不会有线程安全的问题。

ThreadLocal线程封闭:简单易用

使用ThreadLocal来实现线程封闭,线程封闭的指导思想是封闭,而不是共享。所以说ThreadLocal是用来解决变量共享的并发安全问题,多少有些不精确。

概述

ThreadLocal叫做线程变量。意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

原理

ThreadLocal是一个泛型类,能够保证接受任何类型的对象。因为一个线程内可以存在多个ThreadLocal对象,所以其实是ThreadLocal内部维护了一个Map,这个Map不是直接使用的HashMap,而是ThreadLocal实现的一个叫做ThreadLocalMap的静态内部类。而我们使用的get()、set()方法其实都调用了这个ThreadLocalMap类对应的get()、set()方法。

createMap方法

void createMap(Thread t, T firstValue){
    t.threadLocals = new ThreadLocalMap(this,firstValue);
}

ThreadLocalMap是一个静态内部类

static class ThreadLocalMap{
    \\\\\
}

set方法

public void set(T value){
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if(map != null){
        map.set(this,value);
    }else{
        createMap(t,value);
    }
}

get方法

public T get(){
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if(map != null){
        return (T)map.get(this);
    }
    T value = initialValue();
    createMap(t,value);
    return value;
}

最终的变量是放在当前线程的ThreadLocalMap中,并不是存在ThreadLocal上,ThreadLocal可以理解为只是ThreadLocalMap的封装,传递变量值。

ThreadLocal内存泄漏问题

image-20210722093312257

ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,key(ThreadLocal)势必会被GC回收,这样会导致ThreadLocalMap中key为null,而value还存在着强引用,只有thread线程退出以后,value的强引用链条才会断掉。

但如果当前线程迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:

Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value

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

key使用强引用

当ThreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。

key使用弱引用

当ThreadLocalMap的key为弱引用回收ThreadLocal时,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set()、get()、remove()方法时会被清除value值。

ThreadLocal正确的使用方法

每次使用完ThreadLocal都调用它的remove()方法清除数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值