JAVA内存模型 (JMM)和同步以及可见性

一文读懂JMM内存模型 Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。 如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效率并不是很理想,因此Java1.5版本对其进行了重构,现在的Java8仍沿用了Java1.5的版本。 关于并发编程 在并发编程领域,有 阅读详情

可见性:
   一般来说,我们对可见性的定义是一个线程对共享变量值的修改,能够被其他线程
及时的看到,那么这个时候我们一般称这个变量是线程间可见的。

那么什么是共享变量?
      一般来讲,如果一个变量在多个线程的工作内存中都存在有副本,那么这个
    变量就是这几个线程的共享变量。

 那么啥是工作内存呢? 这个时候就是我们的JMM登场了。
Java内存模型(JMM)。描述了Java程序中各种线程共享变量的访问规则,以及在JVM中将变量存储到内存和从内存中读取出来变量这样的底层细节。
在多核系统中,处理器一般有一层或多层的缓存,这些的缓存通过加速数据访问,和
降低共享内存在总线上的通讯。来提高cpu性能。
在处理器层面上,内存模型定义了一个充要条件,“让当前的处理器可以看到其他处理器写入到内存的数据”  以及 “其他处理器可以看到当前处理器写入到内存的数据”。

有些处理器有很强的内存模型,能够让所有的处理器在任何时候任何指定的内存地址上都可以看到完全相同的值,而有的处理器内存模型较弱,在这种处理器中,必须需用内存屏障。来刷新本地处理器缓存并使本地处理器无效。目的是为了让当前处理器能够看到其他处理器的写操作或让其他处理器看到当前处理器的写操作。

在JMM中所有的变量都存储在主内存中,且每个线程都有自己独立的工作内存,里面保存着该线程使用到的变量的副本。(其实就是主内存的一份拷贝)




Class Reordering{
  int x=0, y=0;
public void writer(){
   x=1;
   y=2;
  } 
public void reader(){
 int r1=y;
 int  r2=x;
}
 }
如果在并发中执行这段代码, 读取Y变量将会得到2这个值。 因为这个写入比写到X变量更晚一些。 但是如果重排序发生了, 那么就能发生对Y变量的写入操作,读取2个变量
的操作紧随其后,而且写入到x这个操作能发生程序的结果可能是r1=2 r2=0;

当然不管编译器如果进行重排序, 也要遵循as-if-serial语义。

as-if-serial语义的意思是: 无论如何重排序,程序执行的结果应该与代码顺序执行的结果是一样的。 这点我们一般靠java编译器在单线程下做保证。 打个比喻:
int num1=1; //1
int num2=2; //2
int sum=num1+num2;//3

 在单线程的情况下, 第一 第2 他们的顺序是可以进行重排序的, 但是第三行是不行的.
 所在在单线程的情况下, 我上面所讲的霹雳啪啦的一大堆理论等于放屁, 别急我们看下面。

在多个线程访问下, as-if-serial是没有作用的, 按照一般情况,一个线程不会关注其他线程正在做什么。无论其他线程在计算还是在读写, 他都不太关心。 但是等他需要关心
其他线程在做什么的时候, 就需要做一个事情了, 这个事情就是同步!~
从java内存模型的角度讲,没有正确同步的含义是
    1.一个线程中有一个对变量的写操作
     2.另外一个线程对同一个变量有读操作
     3. 而且写操作和读操作没有通过同步保证顺序

当这些规则被违反的时候,我们就说在这个变量上有一个“数据竞争”(data race)。一个有数据竞争的程序就是一个没有正确同步的程序。

java在语言层面支持可见性和同步的方式是通过:
  synchronized, volatile. 来实现的。 其中volatile并不能实现可见性。
我这里说的并没有包括jdk1.5以后加入的并发包。

JMM对synchornized 有二条规定:
 1.线程解锁前,必须把共享变量的最新值刷新到主内存中  
  2.线程加锁时, 将清空工作内存中共享变量的值,从而使用共享变量时需要从
    主内存中重新读取最新的值。

所以在synchronized代码块退出的时候就保证了主内存是最新的值, 在加锁时就保证
 了加载的是最新的值。 现在大家应该知道synchronized 为啥能同步了吧。


其实synchornized 可以保证可见性。 应该会有人很奇怪为啥sync锁还能保证可见性。 下面我来说不可见的原因有哪些。
在多线程环境下能够造成不可见的原因一般有三点:
 1. 线程交叉执行。
 2. 重排序结合线程交叉执行.
3.共享变量没有及时更新

首先synchronized 已经保证了线程交叉执行的正确性,  所以第一条没用。 而关于第二条
嘿嘿嘿,我上面也写了 单线程情况下不管你怎么重排序都要保证结果一致性。 所以也废除。 第三.....  大家应该能猜得到。  

大家是不是觉得stnchronized 很无敌很牛逼了?  其实他也是有缺点的, 不然不会有大名鼎鼎的java.util.concurrent并发包的出现。
  我以我的理解说几点sync的坏处, 第一 synchronized粒度太粗, 而且该关键字没有提供当线程没获取到锁的情况下的超时逻辑, 而且。 我们应该知道, 一个只读变量他在多线程坏境下是安全的, 因为他并不会修改变量的值,所以捏。 sync锁应该给我们提供一个对互斥区域的并发读。 但是很遗憾他并没有。。。。

 volatile 这个关键字,他可以实现内存的可见性, 深入点来讲,其实他就是加入了内存
  屏障和禁止重排序优化来实现的, 所以我上面所说的不完全都是废话..... 当我们
 对volatile变量执行写操作的时候,会在写操作后加入一条store屏障指令,他会把cpu写缓存器的缓存强制写入的主内存中去。

当对volatile变量执行读操作时,会在读操作前加入一条load屏障指令,他呢,也会强制cpu读到主内存中去。

 其实在java内存模型中一共定义了8条操作指令。他们负责和工作内存打交道。具体的指令..... 我忘了...  大家可以查一下。太晚了,很多东西记不起。有空在更新一下。



细谈java同步之JMM(Java Memory Model) Java内存模型是在硬件内存模型上的更高层的抽象,它屏蔽了各种硬件和操作系统访问的差异性,保证了Java程序在各种平台下对内存的访问都能达到一致的效果。下面我们来一起学习下JMM 立即下载

相关推荐

汇川EASY521 PLC实战指南:从硬件选型到程序架构与故障排查

可编程逻辑控制器(PLC)是工业自动化系统的核心大脑,其工作原理基于循环扫描机制,持续读取输入、执行用户程序并更新输出。这种确定性控制方式,使其在逻辑控制、顺序控制和运动控制中具有不可替代的技术价值,广泛应用于机械设备、生产线和过程控制等场景。对于汇川EASY521这类紧凑型高性能PLC,其核心优势在于集成了运动控制与丰富通讯接口,为中小型设备提供了高性价比的一站式解决方案。在实际应用中,工程师常需处理如“汇川sv660n”伺服驱动器的集成调试,或利用“hslcommunication”等开源库实现C#上位

weixin_42525264的博客 743

Java Memory Model(JMM)关于同步的规定

JMM是一种抽象的概念,它描述的是一组规范,通过这组规范定义了程序中各个变量(实例字段,静态字段,构成数组对象的元素)的访问方式。 JMM关于同步的规定: 1.线程解锁前,必须把共享变量的值刷新到主内存 2.线程加锁前,必须读取主内存的最新的值到工作内存 3.加锁解锁是同一把锁 由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有的成为栈空间),工作内存是每个线程的私有数据区域,而java内存模型中规定所有变量都存储在主内存,主内存是共享的内存区域,所有线程都可以访问,但线程对

lll0101的博客 518

H3C模拟器HCL防火墙路由模式主备配置实验

摘要:本文详细介绍了网络拓扑规划与设备配置方案。运营商仅提供一个接口地址,通过虚IP技术实现双防火墙高可用部署:主备防火墙分别配置10.20.10.1/29和10.20.10.2/29作为实际上联地址,共享10.10.10.2/24虚IP;下联配置172.168.10.0/24网段,核心交换机配置VLAN接口及192.168.10.1、192.168.20.1两个下联接口。文章包含运营商路由器、防火墙(HA配置、VVRP设置)和核心交换机的具体命令行配置步骤,并强调需进行主备切换验证。整个方案实现了单运营商

LQ的博客 1123

JMM(Java 内存模型)详解

所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量)每个线程都有一个私有的本地内存来存储共享变量的副本,并且,每个线程只能访问自己的本地内存,无法访问其他线程的本地内存。本地内存是 JMM 抽象出来的一个概念,存储了主内存中的共享变量副本。线程 A 把本地内存中修改过的共享变量副本的值同步到主内存中去。线程 B到主存中读取对应的共享变量的值。也就是说,JMM 为共享变量提供了可见性的保障。

m0_51431003的博客 7334

PP触发EWM产生PMR捡配

PP触发EWM产生PMR捡配 前言 PMR: Production Material Request 在流程订单/生产订单下达后,可以在EWM中产生PMR,在EWM中, PMR其实代表了ERP中的流程订单/生产订单。 You can use SAP EWM in conjunction with the following PP application components: • Production Orders • Process Orders • Repetitive Manufacturing •

ZevYang的博客 1918

科研效率革命:Zotero与Web of Science联动实现千篇文献一键获取

本文详细介绍了如何利用Zotero与Web of Science联动实现科研文献的高效管理,包括批量导入、智能下载和自动整理千篇文献的技巧。通过精准检索、RIS文件导出和Zotero插件设置,科研人员可以大幅提升文献获取和管理的效率,特别适合开题报告和综述写作等场景。

weixin_29219539的博客 255

并发学习(五) — JAVA内存模型与同步规则

一、Java内存模型(JMM):         它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。一个线程如何和何时能看到其他线程共享变量的值,以及在必须时如何同步访问共享变量。        JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java内存模...

Jae_Wang的博客 880

单片机欠压保护、欠压复位的用法及作用

一. 前言 使用编程环境 :KEIL mdk4 单片机 : NRF24LE1   二. 分析 查询各开发芯片的数据手册,一般在电源管理或者复位设置章节中。以下NRF24LE1为例: Power supply supervisor(电源监控): 电源主管在开机时对系统进行初始化,对即将发生的情况提供预警当电源电压过低而不能安全运行时,系统处于复位状态。 电源管理框图如下:   ...

城南花已开的博客 8402

Java内存模型详解从主内存到工作内存的八种同步操作解析

Java内存模型(Java Memory Model, JMM)是一种抽象规范,它定义了Java程序中各种变量(实例字段、静态字段等)的访问规则,以及在并发条件下,数据如何从主内存同步到各个线程的私有工作内存。JMM的关键目标是解决在多线程环境下,由于缓存一致性、指令重排序等问题导致的可见性、原子性和有序性问题。理解从主内存到工作内存的八种同步操作,是掌握JMM并发基石的核心。

mengjichen的博客 419

YOLOv9改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制

这篇文章带来一个经典注意力模块的汇总,虽然有些模块已经发布很久了,但后续的注意力模块也都是在此基础之上进行改进的,对于初学者来说还是有必要去学习了解一下,以加深对模块,模型的理解。

Limiiiing的博客 2894

【AI 智能体】Windows 环境 Hermes Agent(爱马仕)安装详细过程

Windows 环境 Hermes Agent(爱马仕)安装详细过程

congge_study的博客 1832

java之线程

什么是线程 现代操作系统在运行一个程序时,会为其创建一个进程。例如,启动一个Java程序,操作系统就会创建一个Java进程。现代操作系统调度CPU的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时执行。线程...

Eflyings的博客 343

MSVS C# Matlab的混合编程系列2 - 构建一个复杂(含多个M文件)的动态库:

本节我们尝试将一个有很多函数和文件的Matlab算法文件集成到C#的项目里面。

山云的专栏 2071

JMM内存模型

Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。 如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效率并不是很理想,

lxm55913153的博客 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

全面理解Java内存模型

Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效率并不是很理想,因此Jav

Heaven Wang 的专栏 20万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【java】Java JMM(内存模型)

在并发编程中,当多个线程同时访问同一个共享的可变变量时,会产生不确定的结果,所以要编写线程安全的代码,其本质上是对这些可变的共享变量的访问操作进行管理。导致这种不确定结果的原因就是可见性、有序性和原子性问题,Java 为解决可见性和有序性问题引入了 Java 内存模型,使用互斥方案(其核心实现技术是锁)来解决原子性问题。这篇先来看看解决可见性、有序性问题的 Java 内存模型(JMM)。

DreamSun的博客 690

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【潜意识Java】深度解析Java的内存模型

家人们,今天来聊聊 Java 中至关重要却又常被忽视的部分 ——Java 内存模型(Java Memory Model,JMM)。它可是 Java 程序运行的底层基石,掌控着数据在内存中的存储和访问规则。理解 JMM,对于编写高效、线程安全的 Java 程序非常关键,下面就把我的经验分享给大伙。

潜意识Java的博客 993

Java多线程 JMM之可见性demo

文章目录JMM之可见性demo可见性问题图解 JMM之可见性demo 如下的代码演示了可见性问题 . 一个线程调用给a 和b赋值的方法, 一个线程调用打印a和b的方法. 并进行循环的打印. package com.thread.jmm; /** * 类名称:FieldVisibility * 类描述: 演示可见性问题 * * @author: https://javaweixin6.blog.youkuaiyun.com/ * 创建时间:2020/9/5 14:31 * Version 1.0

Java持续实践 755

【JMM】Java 内存模型

本期内容主要介绍JMM,Java内存模型。

爱编程爱运动的博客 4297

java面试-Java内存模型(JMM)

一、并发编程两个关键问题 线程之间如何通信及线程之间如何同步。java并发采用的是共享内存模型 二、JMM内存模型 Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。 从抽象的角度来看,JMM定义了线程...

weixin_33994444的博客 538

37-Java内存模型

Java内存模型 Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。 如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效...

mbmispig的博客 475

volatile 修饰数组_JAVA的JMM的Volatile的可见性

JMM(Java内存模型Java Memory Model,简称JMM) 本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。JMM关于同步的规定:1 线程解锁前,必须把共享变量的值刷新回主内存2 线程加锁前,必须读取主内存的最新值到自己的工作内存3 加锁解锁是同一把锁由于JVM运行程序的实体是线程,...

weixin_39973009的博客 174
上一篇: java线程池(ThreadPoolExecutor)实例讲解
下一篇: 用Springmvc 返回json数据,填充html 或 jsp页面。
zh_coder
博客等级 码龄12年 31粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值