如何计算ThreadLocal对象的hash值?【ThreadLocal技术】(含AtomicInteger的介绍)

如何计算ThreadLocal对象的hash值?

  • 一、前置知识
  • 二、问题
  • 三、剖析源码:如何计算ThreadLocal对象的hash值?
    • 1、源码
      • 1.1 咱先得知道nextHashCode的起始值
        • 1.1.1 那就要先了解AtomicInteger
          • 创建AtomicInteger
          • 原子的增减操作
          • 原子的加法操作
          • 原子的获取并加法操作
          • 原子的比较并设置
          • 原子的设置操作
        • 1.1.2 继续研究nextHashCode的起始值
    • 2、结论

一、前置知识

  • 先要了解ThreadLocal的基本知识:
    (1)Thread持有的ThreadLocalMap的存储结构,本质是Entry[]数组。
    (2)还了解了ThreadLocal提供的3种重要且常用的API:set(…)、get()、remove()。
  • 可以看:持续积累ThreadLocal技术【ThreadLocal原理 + ThreadLocal的坑 + ThreadLocal的最佳实践】

二、问题

  • 在使用set(…)、get()、remove()时,我们都需要在Entry[]数组中确定一个下标。而这个下标的计算方式都是:int i = key.threadLocalHashCode & (table.length-1);
  • 其中,我们都需要计算ThreadLocal对象的hash值(key.threadLocalHashCode),那么,这个hash值怎么算的?

三、剖析源码:如何计算ThreadLocal对象的hash值?

1、源码

// 首次创建ThreadLocalMap对象的时候
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {...int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);...
}// set(…)、get()、remove()
int i = key.threadLocalHashCode & (table.length-1);
public class ThreadLocal<T> {private final int threadLocalHashCode = nextHashCode();private static AtomicInteger nextHashCode = new AtomicInteger();private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}...
}

1.1 咱先得知道nextHashCode的起始值

private static AtomicInteger nextHashCode = new AtomicInteger();
1.1.1 那就要先了解AtomicInteger

AtomicInteger是Atomic原子类的一种,是Java多线程板块的重要技术。
咱在这里先不深究,只了解AtomicInteger的基本用法,等在深挖“Atomic原子类”技术时再深究。

  • AtomicInteger是java.util.concurrent.atomic包下的一个类,它提供了原子的增减操作,适用于高并发的情况下对整型的操作。

说明:以下代码中的断言(assertEquals)都是成功的。

创建AtomicInteger
public class AtomicIntegerTest {/*** 创建AtomicInteger:使用无参构造函数创建一个初始值为0的AtomicInteger对象*/@Testpublic void testAtomicIntegerWithDefaultInitialValue() {AtomicInteger atomicInteger = new AtomicInteger();assertEquals(0, atomicInteger.get());}
}
/*** 创建AtomicInteger:使用带参构造函数创建一个初始值为10的AtomicInteger对象*/
@Test
public void testAtomicIntegerWithCustomInitialValue() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());
}
原子的增减操作
/*** 原子的增减操作*/
@Test
public void testIncrementAndGet() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());assertEquals(11, atomicInteger.incrementAndGet());assertEquals(10, atomicInteger.decrementAndGet());assertEquals(10, atomicInteger.get());
}
原子的加法操作
@Test
public void testAddAndGet() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());assertEquals(20, atomicInteger.addAndGet(10));assertEquals(20, atomicInteger.get());
}
原子的获取并加法操作
/*** 原子的获取并加法操作*/
@Test
public void testGetAndAdd() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());assertEquals(10, atomicInteger.getAndAdd(10));assertEquals(20, atomicInteger.get());
}
原子的比较并设置
/*** 原子的比较并设置 <br>* 如果当前的值等于预期的值(expected value),则更新成功,否则更新失败。*/
@Test
public void testCompareAndSet() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());assertEquals(true, atomicInteger.compareAndSet(10, 20));assertEquals(20, atomicInteger.get());assertEquals(false, atomicInteger.compareAndSet(10, 30));assertEquals(20, atomicInteger.get());
}
原子的设置操作
/***  原子的设置操作*/
@Test
public void testAtomicIntegerSet() {AtomicInteger atomicInteger = new AtomicInteger(10);assertEquals(10, atomicInteger.get());atomicInteger.set(20);assertEquals(20, atomicInteger.get());
}
1.1.2 继续研究nextHashCode的起始值
  • 示例
public class ThreadLocalTest {@Testpublic void testThreadLocal() {Thread thread1 = new Thread(() -> {// 创建一个ThreadLocal变量,并在一个新的线程内部使用set方法// 这将触发createMap方法,因为此时线程的threadLocals属性为null【这个主观判断是错误的】ThreadLocal<String> threadLocal = new ThreadLocal<>();threadLocal.set("Thread 1");});thread1.start();try {thread1.join();} catch (InterruptedException e) {e.printStackTrace();}}
}
  • 首先,要构造一个场景,即当线程执行到ThreadLocal对象.set(…)时,要走createMap(…)。
  • 然而,线程初始化时,threadLocals已经不为null。
    在这里插入图片描述
    并且,nextHashCode的初始值不是0,而是626627285(十六进制为255992d5),说明之前已经调用了3次getAndAdd方法。
    在这里插入图片描述
    在这里插入图片描述
    第4次调用的时候,threadLocalHashCode变为626627285。

2、结论

  • 总之,nextHashCode一开始为0,每次加0x61c88647。
    那么,按理来说,第1个ThreadLocal对象,它的threadLocalHashCode的值为0、第2个ThreadLocal对象,它的threadLocalHashCode的值为:0 + 0x61c88647,依次类推:0x61c88647 + 0x61c88647、…

private static final int HASH_INCREMENT = 0x61c88647;
这个数是斐波那契数 也叫 黄金分割数(叫啥没那么重要),重要的是让hash 分布非常均匀(这样冲突的概率就小了)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/604120.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS - tf

系列文章目录 前言 PR2 你想看看 tf 能做什么&#xff1f;看看 tf 介绍演示。 一个机器人系统通常有许多随时间变化的三维坐标系&#xff0c;如世界坐标系、基础坐标系、抓手坐标系、头部坐标系等&#xff1a; 5 秒钟前&#xff0c;头部坐标系相对于世界坐标系的位置在哪里&am…

图神经网络|7.1-GCN基本模型概述

图卷积和卷积的差别 图神经网络常见的情况 半监督 实际情况下并不是所有节点都有打上标签。 比如在交通网络中&#xff0c;点对应城市中各个区域的传感器&#xff0c;由于配置的先后问题和经济考虑&#xff0c;有些偏远地区并没有来得及配得上&#xff0c;会缺乏相关数据的支持…

QT常用控件使用及布局

QT常用控件使用及布局 文章目录 QT常用控件使用及布局1、创建带Ui的工程2、ui界面介绍1、界面设计区2、对象监视区3、对象监属性编辑区4、信号与槽5、布局器6、控件1、Layouts1、布局管理器2、布局的dome 2、Spacers3、Buttons4、项目视图组(Item Views)5、项目控件组(Item Wid…

R语言绘制基线资料表

#转换数据类型mydata <- data %>% # 创建新数据集新变量#note#Age=Age, #连续变量#Gender = factor(Gender, levels = c(1, 2),labels = c("Male","Female")) #分类变量transmute(Groups= factor(data$Groups)…

ARM 链接器优化功能介绍

消除公共部分组 链接器可以检测节组的多个副本&#xff0c;并丢弃其他副本。 Arm Compiler for Embedded 生成用于链接的完整对象。因此&#xff1a; 如果 C 和 C 源代码中存在内联函数&#xff0c;则每个对象都包含该对象所需的内联函数的外联副本。如果在 C 源代码中使用…

idea 热更新 JRebel 插件激活使用

下载 在 jetbrains 插件网站点击 show more 加载更多版本找到 2022.4.1 版本https://plugins.jetbrains.com/plugin/4441-jrebel-and-xrebel/versions (opens new window) 安装 请勿直接在idea 中搜索安装, 使用从本地安装, 选择刚刚下载的插件, 激活 在设置中找到 JRebel…

Python count()方法:统计字符串出现的次数与字符串拼接(包含字符串拼接数字)

Python count()方法&#xff1a;统计字符串出现的次数 count 方法用于检索指定字符串在另一字符串中出现的次数&#xff0c;如果检索的字符串不存在&#xff0c;则返回 0&#xff0c;否则返回出现的次数。 count 方法的语法格式如下&#xff1a; str.count(sub[,start[,end]]…

macOS通过外置驱动器备份数据

通过外置驱动器备份数据&#xff08;谨慎操作&#xff09; 1.将外置驱动器连接到您的 Mac。驱动器容量应等于或大于您当前的启动磁盘。驱动器还应该是您可以抹掉的。 2.使用 macOS 恢复功能 抹掉外置驱动器&#xff0c;然后将 macOS 安装 到外置驱动器上。确保您选择的外置驱动…

【无线通信专题】NFC通信模式及可能的应用方式

在文章【无线通信专题】NFC基本原理中我们讲到了NFC工作模式。其中NFC工作模式主要有三种,读写模式、卡模拟模式、点对点模式。 NFC通信模式丰富,NFC Forum定义了三种NFC设备:通用NFCForum设备、读写器设备和标签设备。这些NFC设备可以在三种通信模式下运行,并对应用案例进…

如何使用Plex在Windows系统搭建个人媒体站点公网可访问

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…

定量评估batch correction质量的方法:混合分数

[41] Bttner, M. et al. A test metric for assessing single-cell RNA-seq batch correction. Nat. Methods 16, 43–49 (2019). 被引次数&#xff1a;297 方法介绍与应用来自论文&#xff1a;Matthew Amodio, David Van Dijk, Krishnan Srinivasan, William S Chen, Hussei…

UE4.27.2 网页串流

1、和Unity串流一样安装Node.js 下载地址https://nodejs.org/ 2、下载安装Epic Games启动程序https://www.unrealengine.com/zh-CN/download 3、安装UE4.7.2 4、这里就不安装像素流送演示&#xff0c;选个别的然后创建工程 5、启用PixelStreaming插件 6、设置额外启动参数&am…

【前端规范】

1 前言 HTML 作为描述网页结构的超文本标记语言&#xff0c;一直有着广泛的应用。本文档的目标是使 HTML 代码风格保持一致&#xff0c;容易被理解和被维护。 2 代码风格 2.1 缩进与换行 [强制] 使用 4 个空格做为一个缩进层级&#xff0c;不允许使用 2 个空格 或 tab 字符…

【ZooKeeper高手实战】ZAB协议:ZooKeeper分布式一致性的基石

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

MediaPipeUnityPlugin(最新版)摇摆拳人脸识别

1、从https://github.com/homuler/MediaPipeUnityPlugin 下载Release Package 目前是MediaPipeUnity.0.12.0.unitypackage 2、导入Unity工程 3、打开Face Detection场景&#xff0c;做一些设置修改 1、打开Bootstrap&#xff0c;图像源改成Video&#xff0c;把Solution拖拽到…

day10 用栈实现队列 用队列实现栈

题目1&#xff1a;232 用栈实现队列 题目链接&#xff1a;232 用栈实现队列 题意 用两个栈实现先入先出队列&#xff08;一个入栈&#xff0c;一个出栈&#xff09;&#xff0c;实现如下功能&#xff1a; 1&#xff09;push&#xff1a;将元素x推到队列末尾 2&#xff09;…

基于SpringBoot的医院挂号就诊系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的医院挂号就诊系统,java…

1.7 day5 IO进程线程

互斥锁 #include <myhead.h> char buf[128];//创建临界资源 pthread_mutex_t mutex;//创建锁 void *task(void *arg)//分支线程 {while(1){pthread_mutex_lock(&mutex);//上锁printf("分支线程:buf%s\n",buf);strcpy(buf,"I Love China");pthre…

OpenMMlab导出PointPillars模型并用onnxruntime推理

导出onnx文件 通过mmdeploy的tool/deploy.py脚本容易转换得到PointPillars的end2end.onnx模型。 根据https://github.com/open-mmlab/mmdeploy/blob/main/docs/zh_cn/04-supported-codebases/mmdet3d.md显示&#xff0c;截止目前 mmdet3d 的 voxelize 预处理和后处理未转成 o…

WorkPlus完备的企业级功能堆栈,打造高效的企业移动平台

在如今的数字化时代&#xff0c;企业需要一个完备的功能堆栈来满足复杂的业务需求。WorkPlus作为一个完整的企业级移动平台&#xff0c;拥有完备的企业级功能&#xff0c;如IM、通讯录、内部群、模板群、工作台、权限管控、应用中心、日程管理、邮箱、同事圈、服务号、智能表单…