由一个多线程共享Integer类变量问题引起的。。。

2023-11-20

假设并发环境下,业务代码中存在一些统计操作,为了保证线程安全,开发人员往往会对计数值进行加锁(synchronized),值得注意的是,直接对Integer类型进行加锁,似乎并会达到预期效果,比如下面这段代码:

Integer num = new Integer(0);

public void test() throws InterruptedException {

final int THREAD_SIZE = 10;

final int TASK_SIZE = 100000;

final CountDownLatch latch = new CountDownLatch(THREAD_SIZE);

for (int i = 0; i < THREAD_SIZEi++) {

new Thread() {

public void run() {

for (int j = 0; j < TASK_SIZE / THREAD_SIZEj++) {

synchronized (num) {

num++;

}

}

latch.countDown();

}

}.start();

}

latch.await();

System.out.println("num-->" + num);

}

 

上述代码示例中,总共有10个线程运行,每个线程执行次数为10000(taskSize/threadSize),但是实际程序输出结果却并非是10W次,或许有些同学会觉得诧异,在对计数值numInteger)进行递增操作前,已经执行了加锁操作,为啥还是非线程安全。我们首先来看一下上述程序的线程堆栈信息:

 

 

上图中,每一个线程锁住的资源其实都并非是同一个,这就可以解释为什么对Integer类型进行加锁仍然是非线程安全的

 

或许有同学会说,JavaAPI提供有线程安全的AtomicInteger为啥不用,尽管AtomicInteger是线程安全的,但是接下来我们还是要聊一聊为啥锁不住Integer等原始数据类型的封装类型。

 

JAVA5为原始数据类型提供了自动装/拆箱功能,假设对Integer进行递增/递减操作后,其实HashCode已经发生了变化,synchronized自然也不是同一个对象实例,Integer的源码,如下所示:

 

 

从源码中可以看出,当为Integer赋值数值在-128~127区间时,会从Integer中的一个Integer[]中获取一个缓存的Integer对象,而超出区间值得时候,每次都会new一个新的Integer对象,假设下述这段代码:

Integer num = new Integer(300);

System.out.println("identityHashCode-->" + System.identityHashCode(num));

System.out.println("hashCode-->" + num.hashCode());

num = 300;

System.out.println("identityHashCode-->" + System.identityHashCode(num));

System.out.println("hashCode-->" + num.hashCode());

 

实际程序输出为:

identityHashCode-->627248822

hashCode-->300

identityHashCode-->523481450

hashCode-->300

 内存改变了!即Integer类型超出[-128~127]区间时值的变动都会带来内存的变动

 

Synchronized锁的是对象,也就是identityHashCode所指向的内存地址中的对象实例(根据对象内存地址生成散列值),而hashcode输出的是值得散列值。所以为啥上述程序示例中,identityHashCode每次不同,而hashCode输出的值却相同

 

最后总结下,synchronized(Integer)时,当值发生改变时,基本上每次锁住的都是不同的对象实例,想要保证线程安全,推荐使用AtomicInteger之类会更靠谱。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

由一个多线程共享Integer类变量问题引起的。。。 的相关文章

  • JSON首字母大写问题

    一般如果json中的字段和类里的属性相同 则不需要修改 如果不同则可以在类的属性上添加 JsonProperty 或者 JSONField 但是如果JSON数据或者类中属性首字母大写的话 只能使用 JsonProperty 否则注入的值是n

随机推荐

  • Spring学习笔记总结

    第一章 引言 1 EJB存在的问题 2 什么是Spring Spring是一个轻量级的JavaEE解决方案 整合众多优秀的设计模式 轻量级 1 对于运行环境是没有额外要求的 开源 tomcat resion jetty 收费 weblogi
  • 浅谈音视频开发入门基础及进阶资源分享

    导言 音视频开发涉及的知识面比较广 知识点又相对独立琐碎 入门门槛相对较高 想要对音视频开发具有深入全面的了解 需要在行业深耕多年 本文将简单介绍音视频的采集 编解码 传输 渲染四个技术点并对涉及到的知识点和原理进行解释 希望你可以对音视频
  • JAVA并发:线程安全与Synchorinzed

    1 什么是线程安全问题 线程的合理使用能够提升程序的处理性能 主要有两个方面 第一个是能够利用多核 cpu 以及超线程技术来实现线程的并行执行 第二个是线程的异步化执行相比于同步执行来说 异步执行能够很好的优化程序的处理性能提升并发吞吐量
  • 强符号与弱符号

    文章目录 强符号不允许多次定义 强弱可以共存 都是弱符号 简而言之 在 C 语言中 函数和初始化的全局变量 包括显示初始化为 0 是强符号 未初始化的全局变量是弱符号 在链接器进行链接的时候 有下面的规则 强符号不允许多次定义 即不同的目标
  • 多少个X 蓝桥杯模拟

    问题描述 给定一个字母矩阵 一个 X 图形由中心点和由中心点向四个45度斜线方向引出的直线段组成 四条 线段的长度相同 而且四条线段上的字母和中心点的字母相同 一个 X图形可以使用三个整数 r c L 来描述 其中 r c 表示中心点位于第
  • QT 数据库

    sqlite SQLITE功能简约 小型化 追求最大磁盘效率 支持跨平台 不需要服务器 在本地的 数据库操作基本的功能QT里面都有 可视化软件也很小 有支持关系模式的model In memory database IMDB 即内存数据库
  • java动态代理简单实例

    java动态代理简单实例 package hello import java lang reflect InvocationHandler import java lang reflect Method import java lang r
  • 人工智能与信息化

    众所周知 世界上任何事物都能被存储好然后收藏 唯一不能完全被记载的是电子数据 如手机数据 电脑数据 格物斯坦提醒 因为要管理我们每个人的电子化信息 由于数据量大 操作起来极其不方便 很费时费力 但未来一种通过玻璃光 几秒钟内将电子数据全部安
  • 8.全配置自动生成模块前后端

    文章目录 学习资料 配置式开发全新的模块 快速实现 字典管理 代码生成器详细属性设置 全智能模块开发 查询调整 多表连接 药品模块 生产厂家下拉框 学习资料 https www bilibili com video BV13g411Y7GS
  • PageAbility基本概念

    作者 韩茹 公司 程序咖 北京 科技有限公司 鸿蒙巴士专栏作家 一 Page与AbilitySlice Page Page模板 以下简称 Page 是FA唯一支持的模板 用于提供与用户交互的能力 一个Page可以由一个或多个AbilityS
  • QtWebassembly中文显示支持

    Qt Webassembly中文显示支持 由于webassembly是运行在wasm虚拟环境中的 因此是无法直接访问当前系统字体 如果需要提供中文或其它字体支持需要将字体文件作为资源与应用一起编译打包到wasm中 并在应用中主动加载字体资源
  • HTML5学习(三):布局标签、列表、超链接和id

    1 布局标签 header表示网页的头部 页眉 main表示网页的主体部分 一个页面中只会有一个main footer表示网页的底部 页脚 nav表示网页中的导航 aside和主体相关的其他内容 侧边栏 article表示一个独立的文章 s
  • Linux系统上Hadoop的配置

    目录 1 免密登录 2 设置java安装的根目录 3 hadoop参数配置 hadoop地址配置 1 免密登录 cd ssh ls ssh keygen t rsa P f ssh id rsa ls 多了两个文件 id rsa id rs
  • 杭电ACM 1004题

    原题大概意思就是统计输入字符串中 重复的最大个数 import java util Scanner public class Main public static void main String args Scanner sc new S
  • C++ Primer 第五版 电子书(英文)pdf下载

    C Primer 第五版 电子书 英文 pdf下载下载链接 https pan baidu com s 13BQ93O0g8QaNq4ultcxhKA 提取码获取方式 关注下面微信公众号 回复关键字 1169
  • Tensorflow 机器翻译NMT笔记 1 快速上手

    开始 首先 这篇博客基本基于 https github com tensorflow nmt 的内容来的 作为个人学习的笔记 也当做一个博客内容分享 顺序和Github上的顺序有一些区别 注意咯 首先 这里讲的是一个基于Seq2Seq实现的
  • Python 正则表达式指南

    文章目录 1 正则表达式基础 1 1 简单介绍 1 2 数量词的贪婪模式与非贪婪模式 1 3 反斜杠的困扰 1 4 匹配模式 2 re模块 2 1 开始使用re 2 2 Match 2 3 Pattern 1 正则表达式基础 1 1 简单介
  • Vue2基础框架(js)

    快捷方式 vba div div
  • IO相关-这一篇全了解

    什么是比特 什么是字节 什么是字符 它们长度是多少 各有什么区别 解 Bit最小的二进制单位 是计算机的操作部分 取值0或者1 Byte是计算机操作数据的最小单位由8位bit组成 取值 128 127 Char是用户的可读写的最小单位 在J
  • 由一个多线程共享Integer类变量问题引起的。。。

    假设并发环境下 业务代码中存在一些统计操作 为了保证线程安全 开发人员往往会对计数值进行加锁 synchronized 值得注意的是 直接对Integer类型进行加锁 似乎并不会达到预期效果 比如下面这段代码 Integer num new