博客
关于我
Java ThreadLocal解析
阅读量:446 次
发布时间:2019-03-06

本文共 2039 字,大约阅读时间需要 6 分钟。

简介

ThreadLocal 类似局部变量,解决了单个线程维护自己线程内的变量值(存、取、删),让线程之间的数据进行隔离。(InheritableThreadLocal 特例)

这里涉及三个类,Thread、ThreadLocal、ThreadLocalMap

源码解析

  1. Thread 中有一个 ThreadLocal.ThreadLocalMap 类型的变量 threadLocals。因为ThreadLocalMap变量是跟线程绑定的,所以不存在多线程共享变量之间的并发问题,所以ThreadLocal也就是线程安全的变量。
  2. ThreadLocalMap 是 ThreadLocal 的一个内部静态类,没有继承java.util.Map,定义了一个Entry[]变量,通过Entry的get()方法作为key,value属性作为值来实现一个类似Map的操作
  3. Entry 是 ThreadLocalMap 的一个内部静态类,继承WeakReference<ThreadLocal<?>>,并且定义了一个变量value(Object类型)
  4. ThreadLocal 内部封装了getMap()、Set()、Get()、Remove()4个核心方法,用于操作ThreadLocalMap
  5. 通过getMap()获取每个子线程Thread持有自己的ThreadLocalMap实例,因此它们是不存在并发竞争的
  6. ThreadLocalMap中Entry[]数组存储数据,初始化长度16,大于等于3/4阈值,就进行2倍扩容。
  7. ThreadLocalMap中Entry的key是对ThreadLocal的弱引用,当主线程抛弃掉ThreadLocal对象时,垃圾收集器会忽略这个key的引用而清理掉ThreadLocal对象, 防止了内存泄漏。
  8. 散列算法-魔数0x61c88647,利用一定算法实现了元素的完美散列

看源码可以得出,set、get、remove操作的都是ThreadLocalMap,key为当前线程,value为线程局部变量缓存值

public void set(T value) {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else        createMap(t, value);}public T get() {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null) {        ThreadLocalMap.Entry e = map.getEntry(this);        if (e != null) {            @SuppressWarnings("unchecked")            T result = (T)e.value;            return result;        }    }    return setInitialValue();}public void remove() {    ThreadLocalMap m = getMap(Thread.currentThread());    if (m != null)        m.remove(this);}ThreadLocalMap getMap(Thread t) {    return t.threadLocals;}

问题

不调用remove会内存溢出吗?

大部分场景下是不会的,少数场景才会。

运行时,会在栈中产生两个引用,指向堆中相应的对象。

可以看到,ThreadLocalMap使用ThreadLocal的弱引用作为key,这样一来,假设当ThreadLocal ref和ThreadLocal之间的强引用断开时,即ThreadLocal ref被置为null,下一次GC时,threadLocal对象势必会被回收。
这样,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,比如使用线程池,线程使用完成之后会被放回线程池中,不会被销毁,这些key为null的Entry的value就会一直存在一条强引用链:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。

参考资料

ThreadLocal终极源码剖析

ThreadLocal会内存溢出吗
深入理解Java弱引用

转载地址:http://doufz.baihongyu.com/

你可能感兴趣的文章
MySQL 存储引擎
查看>>
mysql 存储过程 注入_mysql 视图 事务 存储过程 SQL注入
查看>>
MySQL 存储过程参数:in、out、inout
查看>>
mysql 存储过程每隔一段时间执行一次
查看>>
mysql 存在update不存在insert
查看>>
Mysql 学习总结(86)—— Mysql 的 JSON 数据类型正确使用姿势
查看>>
Mysql 学习总结(87)—— Mysql 执行计划(Explain)再总结
查看>>
Mysql 学习总结(88)—— Mysql 官方为什么不推荐用雪花 id 和 uuid 做 MySQL 主键
查看>>
Mysql 学习总结(89)—— Mysql 库表容量统计
查看>>
mysql 实现主从复制/主从同步
查看>>
mysql 审核_审核MySQL数据库上的登录
查看>>
mysql 导入 sql 文件时 ERROR 1046 (3D000) no database selected 错误的解决
查看>>
mysql 导入导出大文件
查看>>
mysql 将null转代为0
查看>>
mysql 常用
查看>>
MySQL 常用列类型
查看>>
mysql 常用命令
查看>>
Mysql 常见ALTER TABLE操作
查看>>
mysql 往字段后面加字符串
查看>>
mysql 快速自增假数据, 新增假数据,mysql自增假数据
查看>>