实现threadlocal

这是我上周的帖子的后续文章,其中我解释了ThreadLocal用法背后的动机 。 从帖子中我们可以回忆起,如果您希望为每个线程拥有一个独立初始化的变量副本,则ThreadLocal确实是一个很酷的概念。 现在,好奇的人可能已经开始问“我如何在Java中实现这样的概念”?

否则,您可能会觉得这不是一个有趣的话题–毕竟,您在这里所需的只是一张地图 ,不是吗? 在处理ThreadLocal <T>时 ,将解决方案实现为HashMap <Thread,T>并以Thread.currentThread()为键似乎是明智的选择。 其实不是那么简单。 因此,如果您有五分钟的时间,请忍受我,我将指导您完成一个漂亮的设计概念。

简单的HashMap解决方案的第一个明显问题是线程安全性。 由于HashMap并不是为支持并发使用而构建的,因此我们无法在多线程环境中安全地使用该实现。 幸运的是,我们不需要花很多时间来解决问题-ConcurrentHashMap <Thread,T>看起来像是天作之合。 检索的完全并发性和可调整的预期更新并发性正是我们首先需要的。

现在,如果您将基于ConcurrentHashMap的解决方案应用于JDK源代码中的ThreadLocal实现,则会带来两个严重的问题。

  • 首先,在Map结构中将线程作为键。 由于该映射永远不会被垃圾回收,因此最终您将永远保持对该线程的引用,从而阻止该线程成为GCd。 不情愿的是,您在设计中造成了巨大的内存泄漏。
  • 第二个问题可能需要更长的时间才能浮出水面,但是即使在幕后进行了巧妙的分段以减少锁争用的机会, ConcurrentHashMap仍然承担同步开销。 在同步需求仍然存在的情况下,您仍然拥有一个结构,可能成为瓶颈的根源。

但是,让我们首先开始解决最大的问题。 如果我们的引用是指向相关线程的最后一个引用,则我们的数据结构需要允许对线程进行垃圾回收。 再次,第一个可能的解决方案是盯着我们看-为什么不使用WeakReferences代替我们通常对对象的引用 ? 因此,实现现在看起来类似于以下内容:

Collections.synchronizedMap(new WeakHashMap<Thread, T>())

现在,我们已经解决了泄漏问题–如果除我们之外没有人引用Thread ,则可以将其定型并进行垃圾回收。 但是我们仍然没有解决并发问题。 现在,解决方案实际上是关于跳出思路思考的样本。 到目前为止,我们已经将ThreadLocal变量视为映射到变量的Threads 。 但是,如果我们颠倒了思路,而是设想了一个解决方案,将ThreadLocal对象映射到每个Thread中的值,该怎么办? 如果每个线程都存储该映射,并且ThreadLocal只是该映射的接口,则可以避免同步问题。 更好的是,我们还避免了GC带来的问题!

确实,当我们打开ThreadLocalThread类的源代码时 ,我们看到这正是在JDK中实际实现该解决方案的方式:

public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals = null;// cut for brevity
}
public class ThreadLocal<T> {static class ThreadLocalMap {// cut for brevity}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T) e.value;}return setInitialValue();}private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;}// cut for brevity
}

所以我们在这里。 Thread类保留对ThreadLocal.ThreadLocalMap实例的引用,该实例是使用对键的弱引用构建的。 以相反的方式构建结构,由于ThreadLocal只能访问当前线程中的值,因此完全避免了线程争用问题。 另外,当Thread完成工作时,映射可以进行垃圾回收,因此我们还避免了内存泄漏问题。

希望您对设计有所了解,因为它确实是解决复杂问题的理想解决方案。 我确实认为阅读源代码是学习新概念的理想方式。 而且,如果您是Java开发人员,那么,比阅读Joshua Bloch和Doug Lea集成到JDK的源代码更好的地方是获得知识的地方?

参考: 如何实现ThreadLocal? 由我们的JCG合作伙伴 Nikita Salnikov Tarnovski在Plumbr Blog博客上获得。

翻译自: https://www.javacodegeeks.com/2013/11/how-is-threadlocal-implemented.html

实现threadlocal

实现threadlocal_ThreadLocal如何实现?相关推荐

最新文章

  1. 大多数人对AI的理解,都是错的
  2. 量子力学工具箱再添利器—科学家提出高效驱动微型引擎概念
  3. Python进阶_wxpy学习:原始数据
  4. python-OpenCV之numpy数组操作
  5. 在winform中,禁止combobox随着鼠标一起滑动!
  6. Redis Cluster 伪集群的搭建
  7. 【LINUX系列】之字符串搜索命令
  8. screenfetch 和 linux_logo安装使用
  9. mysql5.0 执行定时计划
  10. PCL_PCLVisualizer在多线程中的使用问题(viewer spinOnce crash)
  11. JS中使用MD5进行字符串加密
  12. C#点餐系统源码,在线订餐系统源码
  13. windows系统怎么用注册表修改桌面文件路径
  14. 利用虚拟打印机截取打印文件并上传到服务器
  15. 中文和英语中主语、谓语、宾语、定语、状语、补语的定义
  16. 定义图书类Book,具有属性账号id,铭name.作者author和价格price,在创建图书对象时要求通过构造器进行创建,- -次性将四个属性全部赋值
  17. html a5 尺寸,纸型尺寸大小(A1,A2,A3,A4,A5,A6,B1,B2,B3,B4,B5......)
  18. 无盘服务器chkdsk *: /f)修复命令,让你的电脑运行更快点 使用CHKDSK/F磁盘修复命令...
  19. 软件构造心得(5)spec、RI、AF、A的概念辨析之spec
  20. 全方位构建信创生态体系,焱融科技完成海光 CPU 生态兼容性认证

热门文章

  1. codeforces 938E MaxHistory 组合数学
  2. 动态规划练习1 [导弹拦截]
  3. MySQL trim()函数
  4. 【JVM】浅谈双亲委派和破坏双亲委派
  5. Java 多线程 —— 深入理解 volatile 的原理以及应用
  6. 如何quot;优雅quot;地终止一个线程?
  7. Intellij Idea乱码解决方案都在这里了
  8. 3分钟了解“关联规则”推荐
  9. “老师,我不要苹果味的,我要葡萄味的”!
  10. 红歌合唱之团结就是力量