隐蔽的并发错误

欢迎关注公众号 【11来了】 ,持续 中间件源码、系统设计、面试进阶相关内容

在我后台回复 「资料」 可领取 编程高频电子书!
在我后台回复「面试」可领取 30w+ 字的硬核面试笔记!

感谢你的关注!

隐蔽的 synchronized 并发错误

在使用 synchronized 进行单机并发控制时,有一种特殊情况会出现并发控制异常

接下来会说一下为何会出现锁失效问题,通过对字节码进行反编译,查看对应的字节码指令,来寻找并发异常出现的原因!

并发问题复现

代码流程为:

  • 创建两个线程,去执行任务,对 cnt 进行累加操作
  • 为了并发的安全,通过 synchronized 对 cnt 加锁来保证并发安全
public class SynErr implements Runnable {

    public static Integer cnt = 0;
    static SynErr instance = new SynErr();

    @Override
    public void run() {
        for (int i = 0; i <10000; i ++) {
            synchronized (cnt) {
                cnt++;
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(cnt);
    }

}

最终输出结果 理应为 20000 ,但是由于出现了并发问题,导致 cnt 的值总是不到 20000

原因分析

通过在 cnt 对象上加锁,之后在加锁代码内部对 cnt ++,从 代码层面上 来看的话,没有发现什么问题,可以通过对字节码进行反编译,通过 底层的字节码 指令来查找原因

这里可以使用 IDEA 的 jclasslib 工具来查看 class 文件对应的字节码:

image-20241017135501804

接下来查看 run() 方法对应字节码:

image-20241017135708702

接下来解释一下对应字节码:

  • 14 行:monitorenter 即 synchronized 关键字对应的加锁命令,从 14 行开始,表明进入了 synchronized 代码块
  • 26 行:iadd 表明将 cnt 和 1 进行相加,也就是执行了 cnt ++ 的命令
  • 27 行:执行了 Integer.valueOf 方法,新建了一个 Integer 对象,并且在 31 行通过 putstatic 指令赋值给了 cnt ,那么此时 cnt 是一个新的 Integer 对象了

通过 27 行的字节码指令,可以看到,每次执行 cnt ++ 之后,都会创建一个新的 Integer 对象赋值给 cnt,因此两个线程加锁的 cnt 不是一个对象,导致出现并发问题

如何解决呢,对 intance 对象加锁,不对 cnt 加锁就可以了:

synchronized (cnt)
---> 修改
synchronized (intance)
总结

对 cnt 加锁,看似逻辑上没有问题,但最终却出现了并发问题,是因为 JDK 将 java 代码编译为字节码指令,编译后的字节码指令与我们的预期不符,导致出现并发问题,虽然工作中也不会碰到,但是可以借此进一步了解 JVM 中的字节码指令

字节码为了计算方便,为通过栈进行操作数的计算,在第 15 行通过 getstatic 获取 cnt 的 int 值压入栈中,在 25 行将常数 1 压入栈中,在 26 行将栈顶两个整数相加,执行完成 cnt ++ 这行代码,之后将得到的结果赋值给新的 Integer 变量,从而导致 synhronized 锁失效

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Vue+Uniapp汽车保养系统小程序的设计与实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而…

PROFINET转SSI协议模块快速使用说明

Profinet网关PROFINET转SSI协议 PN4SSI模块快速使用说明 * 应用时PNSSI模块时&#xff0c;拨码全部拨到OFF。 (1) 在博途中新建一个项目&#xff0c;通过“选项”——“管理通用站描述文件”添加模块的GSD文件。 选择GSD文件所在的目录&#xff0c;点击安装&#xff1a; (…

天选销冠徐志胜与森马的跨界营销,你get了吗?

在当今这个信息爆炸的时代&#xff0c;品牌如何在众多竞争者中脱颖而出&#xff0c;成为消费者心中的首选&#xff0c;是一个值得深入探讨的问题。知名脱口秀演员徐志胜携手森马推出《绒毛的歌》广告片&#xff0c;以其独特的幽默风格&#xff0c;试图为冬季羽绒服市场注入一股…

CEEMDAN +组合预测模型(Transformer - BiLSTM + ARIMA)

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享&#xff01; EMD、EEMD、FEEMD、CEEMD、CEEMDAN的区别、原理和Python实现&#xff08;一&#xff09;EMD-CSDN博客 EMD、EEM…

解决linux服务器磁盘占满问题(详细,有效,100%解决)

应用场景&#xff1a; 在我们的日常开发中&#xff0c;我们的服务器总是在不知不觉中磁盘莫名奇妙少了很多空间&#xff0c;或者被占满了&#xff0c;如果这时候要想要存储什么文件&#xff0c;突然发现空间不够了。但我们通常也不知道那些文件占用的空间大&#xff0c;这时候…

Linux 内核态,用户态,以及如何从内核态到用户态,交互方式有哪些

一、Linux 内核态&#xff0c;用户态 Linux 内核态&#xff0c;用户态&#xff0c;以及如何从内核态到用户态&#xff0c;我来说下我的理解 很多面试官&#xff0c;面试也是照搬照套&#xff0c;网上找的八股文面试题&#xff0c;面试的人也是背八股文&#xff0c;刚好背到了&…

linux 虚拟环境下源码安装DeepSpeed

第一步&#xff1a;创建虚拟环境&#xff1a; conda create -n deepspeed python3.10 第二步&#xff1a;进入虚拟环境&#xff0c;安装Pytorch 2.3.1 # CUDA 12.1 conda install pytorch2.3.1 torchvision0.18.1 torchaudio2.3.1 pytorch-cuda12.1 -c pytorch -c nvidia 第…

OJ题:随机链表的复制—Java数据结构

目录 随机链表的复制 1. 完整题目 2.错误做法 3.第一次遍历 1.拷贝所有旧节点的val域 2. 串联老节点和新节点 3. 第一次遍历代码&#xff1a; 4.第二次遍历 1. 表示出新链表的节点 2. 表示出新节点的next,random 3. 通过映射关系赋值next,random 4. 第二次遍历代码…

DAY53WEB 攻防-XSS 跨站SVGPDFFlashMXSSUXSS配合上传文件添加脚本

知识点&#xff1a; 1、XSS跨站-MXSS&UXSS 2、XSS跨站-SVG制作&配合上传 3、XSS跨站-PDF制作&配合上传 4、XSS跨站-SWF制作&反编译&上传 XSS分类&#xff1a;https://www.fooying.com/the-art-of-xss-1-introduction/&#xff08;失效了&#xff09; …

案例实践 | 以长安链为坚实底层,江海链助力南通民政打造慈善应用标杆

案例名称-江海链 ■ 实施单位 中国移动通信集团江苏有限公司南通分公司、中国移动通信集团江苏有限公司 ■ 业主单位 江苏省南通市民政局 ■ 上线时间 2023年12月 ■ 用户群体 南通市民政局、南通慈善总会等慈善组织及全市民众 ■ 用户规模 全市近30家慈善组织&#…

【专题】计算机网络概述

1. 计算机网络的作用及其发展史 1.1. 计算机网络的作用 二十一世纪的一些重要特征就是数字化、网络化和信息化&#xff0c;它是一个以网络为核心的信息时代。 网络现在已经成为信息社会的命脉和发展知识经济的重要基础。 信息时代以网络为核心。 (1) 网络 “网络”是一个统称…

selenium:操作滚动条的方法(8)

selenium支持几种操作滚动条的方法&#xff0c;主要介绍如下&#xff1a; 使用ActionChains 类模拟鼠标滚轮操作 使用函数ActionChains.send_keys发送按键Keys.PAGE_DOWN往下滑动页面&#xff0c;发送按键Keys.PAGE_UP往上滑动页面。 from selenium import webdriver from se…

数学考研高分突破:解题思维与速度的双重修炼

随着考研季的临近&#xff0c;众多考生为了在数学这一科目中取得高分&#xff0c;纷纷投入到紧张的复习中&#xff0c;如何在有限的时间内&#xff0c;既提高解题思维&#xff0c;又提升解题速度&#xff0c;成为了许多考生心中的难题&#xff0c;本文将围绕这一主题&#xff0…

绘制YOLOv11模型在训练过程中,精准率,召回率,mAP_0.5,mAP_0.5:0.95,以及各种损失的变化曲线

一、本文介绍 本文用于绘制模型在训练过程中,精准率,召回率,mAP_0.5,mAP_0.5:0.95,以及各种损失的变化曲线。用以比较不同算法的收敛速度,最终精度等,并且能够在论文中直观的展示改进效果。支持多文件的数据比较。 专栏目录:YOLOv11改进目录一览 | 涉及卷积层、轻量化…

SpringMVC后台控制端校验-表单验证深度分析与实战优化

前言 在实战开发中&#xff0c;数据校验也是十分重要的环节之一&#xff0c;数据校验大体分为三部分&#xff1a; 前端校验后端校验数据库校验 本文讲解如何在后端控制端进行表单校验的工作 案例实现 在进行项目开发的时候,前端(jquery-validate),后端,数据库都要进行相关的数据…

【华为】静态路由配置

1.配置接入层&#xff1a; LSW1&#xff08;LSW3同理&#xff09;: vlan batch 10 20 in g0/0/1 port link-type ac port default vlan 10 in g0/0/2 port link-type ac port default vlan 20 in g0/0/24 port link-type tr port tr allow-pass vlan 10 202.配置汇聚层&#xf…

v853扬声器调试

文章目录 1、前言2、环境介绍3、修改设备树4、使用tinymix测试扬声器 1、前言 本文记录v853下的扬声器调试。 2、环境介绍 硬件&#xff1a;韦东山v853 aicit板卡 软件&#xff1a;v853 tina sdk 3、修改设备树 扬声器使用的是v853内置的audio codec&#xff0c;原理图如…

进程的属性

一、进程状态 CPU执行进程代码不是把进程代码执行完毕&#xff0c;才开始执行下一个&#xff0c;而是给每一个进程预分配一个时间片&#xff0c;基于时间片&#xff0c;进行调度轮转。 并行和并发 并行: 多个进程在多个CPU下分别&#xff0c;同时进行运行&#xff0c;这称之…

设计小白必看!一文教你区分原型图和UI图

产品设计过程中&#xff0c;产品经理或UI设计师常常需要在不同的设计阶段产出不同的原型图和UI图。初入职场的产品小白或UI小白很容易将原型图和UI图混淆&#xff0c;不能完全区分它们各自的作用&#xff0c;从而影响了设计流程的效率和效果。本文将详细解析原型图与UI图的定义…

【DS】哈希表,哈希桶的实现

目录 哈希概念哈希冲突哈希函数负载因子哈希冲突的解决闭散列开散列 哈希表闭散列的实现哈希表的结构哈希函数构造函数查找插入删除 哈希表开散列的实现哈希表的结构查找插入删除 哈希表的表长建议是素数 平衡二叉树的学习中&#xff0c;学习及模拟实现了AVL树和红黑树&#xf…