ConcurrentHashMap 在累加键值对个数的 addCount 函数中,使用 ThreadLocalRandom.getProbe() 得到线程的探针哈希值。

在这里,这个探针哈希值的作用是哈希线程,尽量避免线程争用同一数组元素。探针哈希值和 map 里使用的哈希值的区别是,当线程发生数组元素争用后,可以改变线程的探针哈希值,让线程去使用另一个数组元素,而 map 中 key 对象的哈希值,由于有定位 value 的需求,所以它是一定不能变的。

那么这个探针哈希值是在哪计算的呢?带着这个问题我们继续往下看。
ThreadLocalRandom.getProbe() 方法如下:

    /*** Returns the probe value for the current thread without forcing* initialization. Note that invoking ThreadLocalRandom.current()* can be used to force initialization on zero return.*/static final int getProbe() {return UNSAFE.getInt(Thread.currentThread(), PROBE);}

PROBE 是什么?

    // Unsafe mechanicsprivate static final sun.misc.Unsafe UNSAFE;...private static final long PROBE;...static {try {UNSAFE = sun.misc.Unsafe.getUnsafe();Class<?> tk = Thread.class;...PROBE = UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomProbe"));...} catch (Exception e) {throw new Error(e);}}

可以看到 PROBE 表示的是 Thread 类 threadLocalRandomProbe 字段的偏移量。
所以 getProbe 方法的功能就是简单的返回当前线程 threadLocalRandomProbe 字段的值。

接着去 Thread 类看看这个 threadLocalRandomProbe 字段,

    /** Probe hash value; nonzero if threadLocalRandomSeed initialized */@sun.misc.Contended("tlr")int threadLocalRandomProbe;

Thread 类仅仅是定义了这个字段,并没有将其初始化,其初始化工作由 ThreadLocalRandom 类来做。
ThreadLocalRandom 类的 localInit 方法完成初始化工作,

    /*** Initialize Thread fields for the current thread.  Called only* when Thread.threadLocalRandomProbe is zero, indicating that a* thread local seed value needs to be generated. Note that even* though the initialization is purely thread-local, we need to* rely on (static) atomic generators to initialize the values.*/static final void localInit() {// probeGenerator 是一个 AtomicInteger 类型// PROBE_INCREMENT 是一个静态常量,值为 0x9e3779b9int p = probeGenerator.addAndGet(PROBE_INCREMENT);int probe = (p == 0) ? 1 : p; // skip 0long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));Thread t = Thread.currentThread(); // 获取当前线程// 通过 Unsafe 对象初始化当前线程的 threadLocalRandomSeed 字段UNSAFE.putLong(t, SEED, seed);// 通过 Unsafe 对象初始化当前线程的 threadLocalRandomProbe 字段UNSAFE.putInt(t, PROBE, probe);}

SEED 和 PROBE 类似,它表示的是 Thread 类 threadLocalRandomSeed 字段的偏移量。

在 ThreadLocalRandom 类的这个 localInit 方法里,同时初始化了当前线程的 threadLocalRandomSeed 字段和 threadLocalRandomProbe 字段。

所以在 Thread 类 threadLocalRandomProbe 字段上的注释中说:nonzero if threadLocalRandomSeed initialized。就是说如果 threadLocalRandomSeed 字段被初始化了,threadLocalRandomProbe 字段就非零。因为它俩是同时被初始化的。

除此之外,也可以通过 ThreadLocalRandom 类的 advanceProbe 方法更改当前线程 threadLocalRandomProbe 的值。

    /*** Pseudo-randomly advances and records the given probe value for the* given thread.*/static final int advanceProbe(int probe) {probe ^= probe << 13;   // xorshiftprobe ^= probe >>> 17;probe ^= probe << 5;UNSAFE.putInt(Thread.currentThread(), PROBE, probe);return probe;}

ConcurrentHashMap 里的 fullAddCount 方法会调用 ThreadLocalRandom.localInit() 初始化当前线程的探针哈希值;当发生线程争用后,也会调用 ThreadLocalRandom.advanceProbe(h) 更改当前线程的探针哈希值,

private final void fullAddCount(long x, boolean wasUncontended) {int h;if ((h = ThreadLocalRandom.getProbe()) == 0) {ThreadLocalRandom.localInit();      // force initializationh = ThreadLocalRandom.getProbe();wasUncontended = true;}...h = ThreadLocalRandom.advanceProbe(h);...}

关于 ConcurrentHashMap 1.8 中的线程探针哈希相关推荐

  1. java 线程中创建线程_如何在Java 8中创建线程安全的ConcurrentHashSet?

    java 线程中创建线程 在JDK 8之前,还没有办法在Java中创建大型的线程安全的ConcurrentHashSet. java.util.concurrent包甚至没有一个名为Concurren ...

  2. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  3. 如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?(转)

    了解 Java 语言提供了并发包(java.util.concurrent),为高度并发需求提供了更加全面的工具支持. Java 提供了不同层面的线程安全支持.在传统集合框架内部,除了 Hashtab ...

  4. 面试中常见线程的50个问题

    不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java 语言一个重要的特点就是内置了对并发的支持,让 Java 大受企业和程序员的欢迎.大多数待遇丰厚的 Java 开发职位都要求开发者 ...

  5. 【Java并发】-- ConcurrentHashMap如何实现高效地线程安全(jdk1.8)

    文章目录 1.传统集合框架并发编程中Map存在的问题? 2.早期改进策略 3.ConcurrentHashMap采取了哪些方法来提高并发表现(jdk1.8)? 4.ConcurrentHashMap实 ...

  6. Java5中的线程池实例讲解

    Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...

  7. SpringBoot中的线程池,你真的会用么?

    点击关注公众号,Java干货及时送达 来源:blog.csdn.net/m0_37701381/article/details/81072774 前言 前两天做项目的时候,想提高一下插入表的性能优化, ...

  8. Delphi中的线程类

    Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchr ...

  9. Spring Bean 中的线程安全

    在 使用Spring框架时,很多时候不知道或者忽视了多线程的问题.因为写程序时,或做单元测试时,很难有机会碰到多线程的问题,因为没有那么容易模拟多线 程测试的环境.但如果不去考虑潜在的漏洞,它就会变成 ...

最新文章

  1. 织梦怎么改网站主页php,无忧主机教你修改织梦DedeCms网站首页为动态显示的方法...
  2. mfc removemenu 静态菜单 删除_循序渐进的升级,静态体验新款奥迪 A4L
  3. 微软推出 AI 开发免费电子书,手把手教你构建智能聊天机器人
  4. iOS:融云即时通讯快速集成
  5. 到底这个电路是如何振荡的?
  6. 题目1019:简单计算器
  7. 2021数模美赛论文提交具体规则和注意事项汇总!
  8. 基本Socket通信流程
  9. 行驶在傍山的道路上_进藏线上那些唯美弯道,行驶中却充满风险,自驾游要注意几个事项...
  10. 强化学习《基于价值 - DQN其他细节算法》
  11. 点云上的卷积神经网络及其部分应用
  12. 热门开源多媒体库 PJSIP 被爆5个内存损坏漏洞
  13. 计算机管理中看不到iis,win10找不到“internet信息服务(IIS)管理器”怎么办
  14. 面试官:你觉得扫码登录应该怎么实现?
  15. STAR、SMART、6W1H、PDCA原则
  16. html如何画出四个圆圈,css3如何绘制一个圆圆的loading转圈动画
  17. 下载软件一直转圈圈_苹果手机下载不了app,一直转圈怎么办?(附两种解决方法)...
  18. JAVA毕业设计HTML5企业员工管理系统计算机源码+lw文档+系统+调试部署+数据库
  19. 深度测评:贪心AI课程到底怎么样?
  20. ST公司三轴加速度计LIS3DH应用

热门文章

  1. 市场调研-全球与中国FPGA和CPLD开发套件市场现状及未来发展趋势
  2. Lync 2010移动客户端无法登陆的解决办法
  3. linux查看群组所属用户,linux 列出用户所属的所有群组的5种方法
  4. html语言玫瑰花代码,javascript+HTML5的canvas实现七夕情人节3D玫瑰花效果代码
  5. “System.NullReferenceException”类型的异常在 App_Web_2tjb2nqh.dll 中发生,但未在用户代码中进行处理(C#开发)
  6. 中国地图china.js
  7. Code Representation方面的Empirical Studies
  8. 2017百度之星初赛(B)1006小小粉丝度度熊------hdu6119
  9. Poj 2965 The Pilots Brothers‘ refrigerator
  10. 一文看尽中国互动直播行业——低俗无聊?那是现状,不是未来