并发基础—三大问题:可见性、原子性、有序性

文章目录

  • 可见性
  • 原子性
  • 有序性(指令重排)
    • 经典的指令重排案例:单例模式的双重检查锁
    • volatile和synchronize都可以保证有序性
    • 并发压测工具Jcstress证明指令重排会在多线程下出现问题(了解)
    • CPU缓存分为三个级别:L1、L2、L3
    • 寄存器
    • 缓存和寄存器的区别
      • JMM(java memory modle)

可见性

原子性

并发编程时,当一个线程对共享变量的修改操作进行到一半时,另一个线程也可能来操作共享变量,这时就会干扰前一个线程的操作,这也就是原子性问题。

public class AtomicDemo {private static int num = 0;public static void main(String[] args) {List<Thread> list = new ArrayList<>();for (int i = 0; i < 5; i++) {Thread thread = new Thread(() -> {for (int j = 0; j < 1000; j++) {num++;}});list.add(thread);thread.start();}list.forEach(e -> {try {e.join();} catch (InterruptedException ex) {ex.printStackTrace();}});System.out.println(num);}
}

上面代码的运行结果不一定是5000,原因分析如下:
i++编译后对应的JVM指令实际有4条,当只执行了部分操作时,另一个线程同时操作i变量,就会出现原子性问题
在这里插入图片描述

有序性(指令重排)

指令重排:为了保证程序的执行效率,在不影响正确性的前提下,编译器和CPU会对程序中代码进行优化,即指令重排序

  • 指令重排必须保证单线程情况下程序的运行结果是正确的
  • 指令重排在多线程下可能会影响程序运行结果的正确性。

经典的指令重排案例:单例模式的双重检查锁

volatile和synchronize都可以保证有序性

  • synchronize:保证了只有一个线程在操作同步代码块内的代码,而指令重排在单线程的情况下运行结果是正确的

并发压测工具Jcstress证明指令重排会在多线程下出现问题(了解)

<dependency><groupId>org.openjdk.jcstress</groupId><artifactId>jcstress-core</artifactId><version>0.7</version><scope>test</scope>
</dependency>
/**
* 需求:测试指令重排导致程序结果异常情况
* 方法test2中,有可能 flag=true先执行,而num=2后执行,位置交换导致出现方法test1结果r.r1=0
*/
@JCStressTest
//表示对输出结果的处理  Expect.ACCEPTABLE 可以接收的结果
@Outcome(id = {"1", "4"}, expect = Expect.ACCEPTABLE, desc = "ok")
//Expect.ACCEPTABLE_INTERESTING 表示可以接收,并感兴趣的结果
@Outcome(id = "0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "danger")
@State
public class jcstress {int num = 0;boolean flag = false;//线程1执行的代码@Actorpublic void test1(I_Result r) {if (flag) {r.r1 = num + num;} else {r.r1 = 1;}}//线程2执行的代码@Actorpublic void test2(I_Result r) {num = 2;flag = true;}
}

在这里插入图片描述

CPU缓存分为三个级别:L1、L2、L3

CPU的运算速度和内存的访问速度相差比较大,导致CPU每次操作内存都需要耗费大量的等待时间,于是CPU和内存直接增加了缓存设计。

(1)L1(一级缓存)是最接近CPU的,三个缓存中它容量最小,速度最快,每个物理内核上都有个一级缓存L1
(2)L2(二级缓存)速度比L1慢,比L3快,一般情况下每个物理核上都有一个独立的L2
(3)L3(三级缓存)是三个缓存中最大的,同时也是速度最慢的,同一个CPU插槽上的核共用一个三级缓存

寄存器

CPU和一级缓存之间还有寄存器,CPU经常使用同一内存地址的某数据时 ,为减少频繁读取的消耗,就会把该数据存储到寄存器。

缓存和寄存器的区别

(1)缓存是把CPU需要的数据提前缓存起来,减少读取的消耗,但不一定是经常使用的
(2)寄存器是把CPU经常使用的同一内存地址的数据缓存起来,减少读取消耗
在这里插入图片描述
在这里插入图片描述

JMM(java memory modle)

java内存模型和java内存结构不是一回事,java内存模型用于多线程读写共享数据时,保证共享数据的可见性、有序性、原子性,主要是通过synchronize、volatile两个关键字来实现

(1)主内存:主内存是所有线程都能访问,所有共享变量都存储在主内存—方法区和堆
(2)工作内存:每个线程都有自己的工作内存,只存储该线程需要用到的共享变量的副本,线程对变量的所有操作都是工作内存完成的,而不是直接读写主内存的变量,不同线程之间也不能相互访问工作内存中的变量。
(3)jMM内存模型和硬件内存不是一回事,它是一个抽象的概念,不管是工作内存的数据还是主内存的数据,即可能存储到内存,也可能存到CPU的三级缓存或者寄存器中。
在这里插入图片描述

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

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

相关文章

PyTorch 入门学习

目录 PyTorch 定义 核心作用 应用场景 Pytorch 基本语法 1. 张量的创建 2. 张量的类型转换 3. 张量数值计算 4. 张量运算函数 5. 张量索引操作 6. 张量形状操作 7. 张量拼接操作 8. 自动微分模块 9. 案例-线性回归案例 PyTorch 定义 PyTorch 是一个基于 Python 深…

Hive SQL 精进系列:REGEXP_REPLACE 函数的用法

目录 一、引言二、REGEXP_REPLACE 函数基础2.1 基本语法参数详解2.2 简单示例 三、REGEXP_REPLACE 函数的应用场景3.1 去除特殊字符3.2 统一字符串格式 四、REGEXP_REPLACE 与 REPLACE 函数的对比4.1 功能差异4.2 适用场景 五、REGEXP_REPLACE 与 REGEXP 函数的对比5.1 功能差异…

从0开始搭建微服务架构特别篇SpringCloud网关聚合knife4j

前言&#xff1a;总所周知项目开发接口测试需要knife4j&#xff0c;但是&#xff0c;微服务架构中微服务很多&#xff0c;模块地址很多&#xff0c;需要统一管理api测试&#xff0c;就需要聚合在网关统一调用&#xff0c;本章&#xff0c;就说明如何通过网关聚合使用knife4j。 …

Spring Cloud 中的服务注册与发现: Eureka详解

1. 背景 1.1 问题描述 我们如果通过 RestTamplate 进行远程调用时&#xff0c;URL 是写死的&#xff0c;例如&#xff1a; String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 当机器更换或者新增机器时&#xff0c;这个 URL 就需要相应地变…

网页制作15-Javascipt时间特效の记录网页停留时间

01效果图&#xff1a; 02运用&#xff1a; window.setTimeout&#xff08;&#xff09;刷新function&#xff08;&#xff09;函数document.forms&#xff08;&#xff09;&#xff1a;表单if条件语句window.alert&#xff08;&#xff09;窗口警示 03、操作代码&#xff1a;…

【Rust基础】排序和分组

排序 简单排序 整数排序 #[test] fn test_sort(){let mut list vec![1, 5, 3, 2, 4];list.sort(); //✔assert_eq!(list, vec![1, 2, 3, 4, 5]); }小数排序 #[test] fn test_sort(){let mut list vec![1, 5, 3, 2, 4];//❌ 不能直接使用sort&#xff0c;因为f32和f64未实现O…

C++ std::list超详细指南:基础实践(手搓list)

目录 一.核心特性 1.双向循环链表结构 2.头文件&#xff1a;#include 3.时间复杂度 4.内存特性 二.构造函数 三.list iterator的使用 1.学习list iterator之前我们要知道iterator的区分 ​编辑 2.begin()end() 3.rbegin()rend() 四.list关键接口 1.empty() 2. size…

996引擎 - 红点系统

996引擎 - 红点系统 总结NPC 红点(TXT红点)Lua 红点1. Red_Point.lua2. UI_Ex.lua参考资料以下内容是在三端 lua 环境下测试的 总结 红点系统分几个部分组成。 M2中设置变量推送。 配置红点表。 Envir\Data\cfg_redpoint.xls 2.1. UI元素中找到ID填写 ids 列。 主界面挂载…

C语言——变量与常量

C语言中的变量与常量&#xff1a;简洁易懂的指南 在C语言编程中&#xff0c;变量和常量是最基本的概念之一。理解它们的区别和使用方法对于编写高效、可维护的代码至关重要。本文将详细介绍C语言中的变量和常量&#xff0c;并通过图表和代码示例帮助你更好地理解。 目录 什么…

PySide(PyQt),使用types.MethodType动态定义事件

以PySide(PyQt)的图片项为例&#xff0c;比如一个视窗的场景底图是一个QGraphicsPixmapItem&#xff0c;需要修改它的鼠标滚轮事件&#xff0c;以实现鼠标滚轮缩放显示的功能。为了达到这个目的&#xff0c;可以重新定义一个QGraphicsPixmapItem类&#xff0c;并重写它的wheelE…

K8S学习之基础三十一:k8s中RBAC 的核心概念

Kubernetes (k8s) 中的 RBAC&#xff08;Role-Based Access Control&#xff0c;基于角色的访问控制&#xff09;是一种用于管理用户和服务账户对集群资源访问权限的机制。RBAC 允许管理员通过定义角色&#xff08;Role&#xff09;和角色绑定&#xff08;RoleBinding&#xff…

【eNSP实战】三层交换机使用ACL实现网络安全

拓图 要求&#xff1a; vlan1可以访问Internetvlan2和vlan3不能访问Internet和vlan1vlan2和vlan3之间可以互相访问PC配置如图所示&#xff0c;这里不展示 LSW1接口vlan配置 vlan batch 10 20 30 # interface Vlanif1ip address 192.168.40.2 255.255.255.0 # interface Vla…

软考系统架构师 — 1 考点分析

目录 1 考点总结 1 考点总结 章节 内容 真题考察 绪论 1. 绪论 不考 计算机相关知识 2. 计算机系统基础知识&#xff0c;新增计算机硬件、嵌入式、计算机语言、系统工程 对应计算机组成结构、操作系统、数据库、计算机网络、多媒体等知识点&#xff0c;整体分值在 10 …

在Eclipse 中使用 MyBatis 进行开发,通常需要以下步骤:

在Eclipse 中使用 MyBatis 进行开发&#xff0c;通常需要以下步骤&#xff1a; 1. 创建 Maven 项目 首先&#xff0c;在 Eclipse 中创建一个 Maven 项目。如果你还没有安装 Maven 插件&#xff0c;可以通过 Eclipse Marketplace 安装 Maven 插件。 打开 Eclipse&#xff0c;选…

错误记录: git 无法连接到github

错误记录: git 无法连接到github 今天, 新建了一个github仓库, 但从本地怎么都push不上去.并报错 gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository e…

k8s 配置两个deployment主机级别互斥部署

在 Kubernetes 中&#xff0c;要实现两个 Deployment 的 Pod 在主机级别互斥部署&#xff0c;可以使用 podAntiAffinity 配置。通过设置 podAntiAffinity&#xff0c;可以确保两个 Deployment 的 Pod 不会被调度到同一节点上。 实现步骤 定义 Deployment&#xff1a; 为每个…

Unity中WolrdSpace下的UI展示在上层

一、问题描述 Unity 中 Canvas使用World Space布局的UI&#xff0c;想让它不被3d物体遮挡&#xff0c;始终显示在上层。 二、解决方案 使用shader解决 在 UI 的材质中禁用深度测试&#xff08;ZTest&#xff09;&#xff0c;强制 UI 始终渲染在最上层。 Shader "Custo…

五子棋小游戏-简单开发版

一、需求分析 开发一个基于 Pygame 库的五子棋小游戏&#xff0c;允许两名玩家在棋盘上轮流落子&#xff0c;当有一方达成五子连珠时游戏结束&#xff0c;显示获胜信息&#xff0c;并提供退出游戏和重新开始游戏的操作选项。 1.棋盘显示 &#xff1a; 显示一个 15x15 的五子棋…

基于C#的以太网通讯实现:TcpClient异步通讯详解

基于C#的以太网通讯实现&#xff1a;TcpClient异步通讯详解 在现代工业控制和物联网应用中&#xff0c;以太网通讯是一种常见的数据传输方式。本文将介绍如何使用C#实现基于TCP协议的以太网通讯&#xff0c;并通过异步编程提高通讯效率。我们将使用TcpClient类来实现客户端与服…

小秋的矩阵

0小秋的矩阵 - 蓝桥云课 问题描述 给你一个 n 行 m 列只包含 0 和 1 的矩阵&#xff0c;求它的所有子矩阵中&#xff0c;是方阵而且恰好包含 k 个 0 的数量。 方阵是行数和列数相等的矩阵。 子矩阵是从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵&#xff08;保…