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

java ThreadLocal

private ThreadLocal threadLocal = new ThreadLocal();
threadLocal.set(0);
(int) threadLocal.get();

上面三行代码分别是定义、赋值和取值。

介绍:

我们只需要实例化对象一次,并且也不需要知道它是被哪个线程实例化。虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用ThreadLocal的set()方法设置的值。即使是两个不同的线程在同一个ThreadLocal对象上设置了不同的值,他们仍然无法访问到对方的值。

需要框架源码的朋友可以看我个人简介联系我,推荐分布式架构源码。 

各个线程赋值读取互补干扰的原理:

源码中有一个ThreadLoalMap类型的东西,理解成map类型即可。

详解一下取值过程,调用ThreadLocal的get方法时,会先调用getMap(t)获取到ThreadLoalMap的集合,其中参数t为当前线程(Thread.currentThread()),getMap方法表示每个线程对象中都维护有这么个ThreadLoalMap对象集合。

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();
}
ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}

然后,调用该集合的getEntry方法,参数就是ThreadLocal对象本身,ThreadLocal的hash值和table.length构成了Entry的键。

private Entry getEntry(ThreadLocal<?> key) {int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.get() == key)return e;elsereturn getEntryAfterMiss(key, i, e);
}

总结下:

每个线程都维护有一个ThreadLocalMap对象集合,他的键就是ThreadLocal对象的hash(相当于这么个东西),这样A、B两个线程就会各自维护一个ThreadLocalMap对象集合,共用一个ThreadLocal对象的hash值当作其中的键,就相当于A线程的ThreadLocalMap有共用的hash键,B线程的ThreadLocalMap也有一个共用的hash键。这样就不会冲突了,有点绕,多查资料多理解。

InheritableThreadLocal其中还有这么个东西,InheritableThreadLocal类是ThreadLocal类的子类。ThreadLocal中每个线程拥有它自己的值,与ThreadLocal不同的是,InheritableThreadLocal允许一个线程以及该线程创建的所有子线程都可以访问它保存的值。相当于一个类定义成protected。

1. 每个Thread实例内部,有二个ThreadLocalMap的K-V容器实例(分别对应threadLocals及inheritableThreadLocals), 容器的元素数量,即为Thread实例里的ThreadLocal实例个数
2. ThreadLocalMap里的每个Entry的Key与ThreadLocal实例的HashCode相关(这样,多个ThreadLocal实例就不会搞混)
3. 每个ThreadLocal实例使用set赋值时,实际上是在ThreadLocalMap容器里,添加(或更新)一条Entry信息
4. 每个ThreadLocal实例使用get取值时,从ThreadLocalMap里根据key取出value 。

关于内存泄漏问题:

通过之前的分析已经知道,当使用ThreadLocal保存一个value时,会在ThreadLocalMap中的数组插入一个Entry对象,按理说key-value都应该以强引用保存在Entry对象中,但在ThreadLocalMap的实现中,key被保存到了WeakReference对象中,源码中是继承WeakReference对象了。

static class Entry extends WeakReference<ThreadLocal<?>>

ThreadLocal在ThreadLocalMap中是以一个弱引用身份被Entry中的Key引用的,因此如果ThreadLocal没有外部强引用来引用它,那么ThreadLocal会在下次JVM垃圾收集时被回收。这个时候就会出现Entry中Key已经被回收,出现一个null Key的情况,外部读取ThreadLocalMap中的元素是无法通过null Key来找到Value的。因此如果当前线程的生命周期很长,一直存在,那么其内部的ThreadLocalMap对象也一直生存下来,这些null key就存在一条强引用链的关系一直存在:Thread --> ThreadLocalMap-->Entry-->Value,这条强引用链会导致Entry不会回收,Value也不会回收,但Entry中的Key却已经被回收的情况,造成内存泄漏。

但是JVM团队已经考虑到这样的情况,并做了一些措施来保证ThreadLocal尽量不会内存泄漏:在ThreadLocal的get()、set()、remove()方法调用的时候会清除掉线程ThreadLocalMap中所有Entry中Key为null的Value,并将整个Entry设置为null,利于下次内存回收。

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

相关文章:

  • MySQL高级篇第6章(索引的数据结构)
  • Unity 性能优化三:动画模块、物理模块
  • 延迟函数
  • IBM报告:2023数据泄露平均成本将达到445万美元
  • 20.3 HTML 表格
  • flutter项目运行时一直卡在Running Gradle task ‘assembleDebug‘解决办法
  • “深入理解Spring Boot:从入门到精通“
  • IP 工具
  • Linux - 进程概念(进程状态、优先级)
  • k8s概念-deployment
  • Flutter 调试工具篇 | 壹 - 使用 Flutter Inspector 分析界面
  • 什么是云原生和 CNCF?
  • 数据结构——单链表
  • 微信小程序手写签字版
  • 机器学习十大经典算法
  • HCIP-datacom-821题库真题和机构资料
  • javaSE,javaEE,javaME的区别
  • mysql innodb一些知识点
  • Android 面试题 应用对内存是如何限制 八
  • 赛车游戏——【极品飞车】(内含源码inscode在线运行)
  • 无人机调试笔记——常见参数
  • 如何快速实现多人协同编辑?
  • ThinkPHP 一对多关联
  • C++基础篇(二)基本数组及示例
  • C++多态练习题
  • ELD透明屏在智能家居中有哪些优点展示?
  • 第十三章 利用PCA简化数据
  • 开源中文分词Ansj的简单使用
  • 251_多线程_创建一个多线程的图像处理应用,其中每个线程负责对一部分图像进行处理,然后将处理后的结果合并为最终图像
  • [吐槽Edge浏览器]关于Edge浏览器的闪退问题