当前位置: 首页 > news >正文

ThreadLocal介绍

文章目录

  • ThreadLocal
    • 源码分析:
      • set方法
      • get方法
      • remove方法
    • ThreadLocal内存泄漏问题

ThreadLocal

ThreadLocal提供了线程局部变量,每个线程都可以通过set和get方法来对这个变量进行操作,但不会和其他线程的局部变量冲突,实现了线程的数据隔离

源码分析:

set方法

public void set(T value) {Thread t = Thread.currentThread();//getMap就是为了获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null)//如果map存在就直接以这个ThreadLocal为键,设置键和值map.set(this, value);else//否则就为他创建一个ThreadLocalMap,并设置第一个键和值createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}

get方法

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {//如果当前线程的ThreadLocalMap存在,就尝试获取对应键值对ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}//如果threadLocals不存在或者当前的ThreadLocal不存在于这个map中return setInitialValue();
}
private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)//当前ThreadLocal不存在于map中,就加上,设置value为空map.set(this, value);else//如果map不存在就创建,并设置键值createMap(t, value);return value;
}
protected T initialValue() {return null;
}

remove方法

public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);
}
private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {//弱引用中的清除方法e.clear();//将key为null的键值对清除掉,get和set方法底层也有用到expungeStaleEntry(i);return;}}
}
private static int nextIndex(int i, int len) {return ((i + 1 < len) ? i + 1 : 0);
}

总结:

可以看出,ThreadLocal中并不存储值,只是作为一个key来让线程从ThreadLocalMap中获取value,从而实现了线程之间的数据隔离

  • 每个线程都维护着一个ThreadLocalMap,ThreadLocalMap是ThreadLocal的内部类
  • ThreadLocal中的set,实际上是向当前线程的ThreadLocalMap中设置值,键为创建的ThreadLocal对象

ThreadLocal内存泄漏问题

内存泄漏:程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况

内存溢出:要求分配的内存超过了系统能给的

ThreadLocal中作为map中的key使用,而且ThreadLocalMap中的key是弱引用,弱引用对象在gc时会被回收,而ThreadLocalMap和Thread的生命周期一样长,就会存在key为null的情况,value访问不到,从而引发内存泄漏。所以,使用ThreadLocal时最后最好调用remove方法显式调用expungeStaleEntry方法手动删除key为null的value,防止value的积累

ThreadLocal的get和set方法某些时候也会调用expungeStaleEntry方法,但这是不及时的,而且不一定每次都会执行

http://www.lryc.cn/news/310193.html

相关文章:

  • 【Linux系统化学习】线程概念
  • Redis集群模式
  • 执行go get xxx报错
  • MATLAB基础语法与实践
  • 智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护)
  • 回归预测 | Matlab实现RIME-BP霜冰算法优化BP神经网络多变量回归预测
  • LeetCode15:三数之和
  • 【详识JAVA语言】面向对象程序三大特性之三:多态
  • nginx(三)实现反向代理客户端 IP透传
  • 深入Java日志框架及其最佳实践
  • threejs显示本地硬盘上的ply文件,通过webapi
  • 代码随想录day10(2)字符串:反转字符串Ⅱ (leetcode541)
  • 【MySQL】_联合查询基础表
  • InnoDB存储引擎对MVCC的实现
  • 【精选】Java项目介绍和界面搭建——拼图小游戏 中
  • C++ //练习 10.16 使用lambda编写你自己版本的biggies。
  • 【misc | CTF】BUUCTF 二维码
  • OSCP靶场--Resourced
  • Vue路由(黑马程序员)
  • 【Java程序员面试专栏 算法思维】一 高频面试算法题:排序算法
  • sql注入之sqli-labs-less-1 错误注入
  • React withRouter的使用及源码实现
  • c++之旅——第四弹
  • Mysql整理-主从复制
  • 100个百万阅读公众号爆文案例
  • UnityAPI的学习——Transform类
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • GO基本类型
  • 怎么快速编辑视频
  • 基于vue-office实现docx、xlsx、pdf文件的在线预览