ThreadLocal(底层原理/内存泄漏/应用)
2021-03-02 13:53:11 0 举报
AI智能生成
ThreadLocal(底层原理/内存泄漏/应用)
作者其他创作
大纲/内容
阅读导航
线程 👉
CPU+JMM 👉
CAS+Volatile 👉
Synchronized 👉
JUC 👉
线程池 👉
ThreadLocal
为每个线程创建一个变量的副本,每个线程可以单独访问自己的副本,而不与其他线程共享,当前线程结束后GC
使用
声明ThreadLocal对象:ThreadLocal<Person> tl = new ThreadLocal<>();
调用方式
tl.set(new Person());
tl.get()
实现原理
每个线程(Thread类)都有一个ThreadLocalMap对象(threadLocals),key为threadLocal对象(tl)的弱引用,value为对应的副本值
ThreadLocalMap数据结构:类似 HashMap 的 key-value 键值对,底层实现是table[]数组,没有链表结构,使用开放定址法解决hash冲突
源码分析
set()
先获取当前线程:Thread t = Thread.currentThread();
再获取属于当前线程的map对象
ThreadLocalMap map = getMap();
return t.threadlocals;(线程类的属性)
return t.threadlocals;(线程类的属性)
通过 map.set(this, value)
底层 new Entry(key, value) 给数组赋值,Entry类继承自WeakReference
Entry类的构造方法中有 super(key):创建弱引用对象指向key(tl 对象)
Entry类的构造方法中有 super(key):创建弱引用对象指向key(tl 对象)
弱引用防止
内存泄漏
内存泄漏
ThreadLocal<Person> tl = new ThreadLocal<>(); tl 指向ThreadLocal对象,强引用
tl.set(new Person()); => map.set( key, Person); key是指向ThreadLocal对象的 弱引用
这样当外部强引用消失时(tl=null或者方法运行完弹栈),ThreadLocal对象能够得到回收
否则如果map的key也是强引用,则只要线程还在运行,ThreadLocal的内存就不会被释放
否则如果map的key也是强引用,则只要线程还在运行,ThreadLocal的内存就不会被释放
get()
拿到当前线程,获取map对象,通过Entry中的key获取value后返回
remove()
拿到当前线程,获取map对象,将 map 中对应 tl 的 key 移除
什么地方存在内存泄露?
①外部强引用消失时,ThreadLocal对象可能无法回收,导致内存泄漏(jdk优化:通过弱引用已解决)
②ThreadLocal对象被回收后,map中Entry的value就访问不到了,如果线程一直运行则导致内存泄漏
解决②:ThreadLocal用完后,一定要调用remove()方法(线程池慎用ThreadLocal)
应用
线程本地变量/存储,避免了将对象作为参数传递的麻烦
延伸:把变量设置为static不是也可以传递吗?
static有局限性,多线程访问时会有数据污染
threadlocal可以保证每个线程访问私有的变量
Spring中@Transactional注解,使用ThreadLocal存储数据库连接connection,保证事务方法每次拿到的都是同一个connection
Spring中Bean在singleton作用域时,使用ThreadLocal解决共享变量的线程安全问题
关于作者
我的博客 👉
微信公众号 👉
GitHub 导航 👉
ProcessOn 主页 👉
0 条评论
下一页