【高并发】为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题?看完这篇我懂了!

简介: 我们在32位多核CPU的计算机上以多线程的方式读写long类型的共享变量时,线程已经将变量成功写入了内存,但是重新读取出来的数据和之前写入的数据不一致,这到底是为什么呢?

大家好,我是冰河~~

写在前面

大冰:小菜童鞋,前几天讲的知识点复习了吗?

小菜:复习了,大冰哥,我回去关注了你的公众号,收藏和转发了你的文章,看了好几遍呢!!

大冰:好的,一定要好好复习啊,今天,我们来分析一个诡异的问题:为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题呢? 今天的内容很重要,它能够帮助你更加深刻的理解线程的原子性问题,一定要好好听!

诡异的问题

我们在32位多核CPU的计算机上以多线程的方式读写long类型的共享变量时,线程已经将变量成功写入了内存,但是重新读取出来的数据和之前写入的数据不一致,这到底是为什么呢?

原因分析

其实,造成这个问题的根本原因就是线程的原子性问题,而线程的原子性问题最终的“幕后黑手”是线程切换,如果能够禁用线程切换就能够解决这个问题了!在操作系统层面来看,操作系统做线程切换需要依赖CPU的中断机制,所以说,禁止CPU发生中断就能够禁止线程切换。

这种方案在单核CPU上是可行的,但是并不适合多核CPU。

其实,就分析为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题,我们需要从数据类型占用的存储空间来分析。long型变量是64位的,在32位CPU上执行写操作会被拆分成两次写操作(分别是写高32位和写低32位)。我们可以用下图来表示。

32位单核CPU

在32位单核CPU场景下,同一时刻只有一个线程执行,禁止CPU中断,也就是说,在单核CPU上,操作系统不会重新调度线程,实际上,也就是禁止了线程切换。如果一个线程获取到CPU资源,就可以一直执行下去,直到线程结束为止。在这个线程中,对于long型变量的两次写操作,要么都被执行,要么都没有被执行,两次写操作具有原子性,不会出现写入的数据和读取的数据不一致的情况。

我们可以简单的使用下图来表示32位单核CPU写long型数据这个过程。

由上图我们可以看出,在32位单核CPU中,禁止了线程切换之后,所有的线程都是串行执行的,对于long型变量的两次写操作,要么都被执行,要么都没有被执行,两次写操作具有原子性,不会出现写入的数据和读取的数据不一致的情况。

32位多核CPU

在32位多核CPU场景下,同一时刻,可能有两个甚至更多的线程在同时执行。假设有两个线程分别是线程A和线程B,线程A执行在CPU-01上,线程B执行在CPU-02上,此时,禁用CPU中断,只能保证在每个CPU上执行的线程是连续的,并不能保证同一时刻只有一个线程执行,如果线程A和线程B同时写long型变量的高32位的话,那么,就有可能出现诡异的Bug问题,也就是说,明明已经将变量成功写入内存了,但是重新读取出来的数据却不是自己写入的!!

我们可以简单的使用下图来表示32位多核CPU并发写long型数据这个过程。

由上图我们可以看出,在32位多核CPU中,如果有多个线程同时对long类型的数据进行写操作,即使中断CPU操作,也只能保证在每个CPU上执行的线程是连续的,并不能保证同一时刻只有一个线程执行。如果多个线程同时写long型变量的高32位的话,那么,就有可能出现诡异的Bug问题。

总结

long型变量是64位的,在32位CPU上执行写操作,会被拆分成写高32位和写低32位两部分,如果此时有多个线程同时写long型变量的高32位的话,就有可能出现诡异的Bug问题。

注意:不只是long型变量,在32位多核CPU上并发写64位数据类型的数据,都会出现类似的诡异问题!!!

如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发编程技术。

写在最后

大冰:这就是今天的主要内容了,今天的内容非常重要,它能够帮助你更加深刻的理解并发编程的原子性问题,小菜童鞋,回去后一定要好好复习下。

小菜:好的,大冰哥,回去我一定好好复习。

最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。

目录
相关文章
|
7月前
|
SQL 数据管理 网络安全
数据管理DMS操作报错合集之DMS的CPU使用率达到100%,如何解决
数据管理DMS(Data Management Service)是阿里云提供的数据库管理和运维服务,它支持多种数据库类型,包括RDS、PolarDB、MongoDB等。在使用DMS进行数据库操作时,可能会遇到各种报错情况。以下是一些常见的DMS操作报错及其可能的原因与解决措施的合集。
|
Oracle 关系型数据库 Linux
解决在linux服务器上部署定时自动查找cpu,内存,磁盘使用量,并将查询结果写入数据库的脚本,只能手动运行实现插库操作
问题描述:将脚本名命名为mortior.sh(以下简称mo),手动执行脚本后查询数据库,表中有相应的信息,放入自动执行队列中,脚本被执行,但是查询数据库,并没有新增数据。
86 0
|
4月前
|
Java 编译器 Linux
JVM/编译器/CPU,究竟谁是卧底?一个曾经困扰我一个月的 bug
任何复杂的系统都可能因为一个小小的疏漏而无法运转,本文记录了一个困扰作者一个月的 bug 最终拨云见日的过程。
|
6天前
|
缓存 NoSQL Java
高并发场景秒杀抢购超卖Bug实战重现
在电商平台的秒杀活动中,高并发场景下的抢购超卖Bug是一个常见且棘手的问题。一旦处理不当,不仅会引发用户投诉,还会对商家的信誉和利益造成严重损害。本文将详细介绍秒杀抢购超卖Bug的背景历史、业务场景、底层原理以及Java代码实现,旨在帮助开发者更好地理解和解决这一问题。
35 12
|
5月前
|
NoSQL Redis 开发工具
Redis性能优化问题之检查 Redis 实例是否启用了透明大页机制,如何解决
Redis性能优化问题之检查 Redis 实例是否启用了透明大页机制,如何解决
|
6月前
|
分布式计算 DataWorks 监控
DataWorks操作报错合集之遇到“OSERROR: argument list too long”的错误,该如何处理
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
67 1
|
7月前
|
关系型数据库 MySQL Java
实时计算 Flink版操作报错之整内存和cpu分配之后启动报错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
7月前
|
存储 缓存 Java
揭秘计算机指令执行的神秘过程:CPU内部的绝密操作
本文介绍了计算机指令和CPU如何执行指令。它解释了计算机指令可以被视为CPU所理解的语言,不同的CPU支持不同的指令集。文中重点介绍了MIPS指令集作为示例。同时,还描述了CPU的内部处理过程,包括控制单元、算术逻辑单元和数据单元。文章最后讨论了CPU和内存之间通过地址和数据总线进行的数据传输。
273 1
|
7月前
|
分布式计算 并行计算 Hadoop
【云计算与大数据计算】分布式处理CPU多核、MPI并行计算、Hadoop、Spark的简介(超详细)
【云计算与大数据计算】分布式处理CPU多核、MPI并行计算、Hadoop、Spark的简介(超详细)
347 0
|
运维 Java
高并发下Netty4底层bug导致直接内存溢出分析
高并发下Netty4底层bug导致直接内存溢出分析
199 0
下一篇
DataWorks