Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >并发学习笔记06-顺序一致性

并发学习笔记06-顺序一致性

作者头像
WindCoder
发布于 2020-01-21 07:35:19
发布于 2020-01-21 07:35:19
8260
举报
文章被收录于专栏:WindCoderWindCoder

并发学习系列以阅读《Java并发编程的艺术》一书的笔记为蓝本,汇集一些阅读过程中找到的解惑资料而成。这是一个边看边写的系列,有兴趣的也可以先自行购买此书学习。

顺序一致性

顺序一致性内存模型是一个理论参考模型,在设计的时候,处理器的内存模型和编程语言的内存模型都会以顺序一致性内存模型作为参照。

数据竞争与数据一致性

当程序未正确同步时,就可能存在数据竞争。

Java内存模型规范对数据竞争的定义如下:在一个线程中写一个变量,在另一个线程读同一个变量,而且写和读没有通过同步来排序。

如果一个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序。

JMM对正确同步的多线程程序的内存一致性做了如下保证:如果程序是正确同步的,程序的执行将具有顺序一致性(Sequentially Consistent —— 即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同

顺序一致性内存模型

顺序一致性模型是一个被计算机科学家理想化了的理论参考模型,它为程序员提供了极强的内存可见性保证

顺序一致性内存模型有两大特性:

  • 1.一个线程中的所有操作必须按照程序的顺序来执行
  • 2.(不管程序是否同步)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见。
顺序一致性内存模型的视图

在概念上,顺序一致性模型有一个单一的全局内存,这个内存通过一个左右摆动的开关可以连接到任意一个线程,同时每一个线程必须按照程序的顺序来执行内存读/写操作。

在任意时间点最多只有一个线程可以连接到内存。

当多个线程并发执行时,图中的开关装置能把所有线程的所有内存读/写操作串行化(即在顺序一致性模型中,所有操作之间具有全序关系)。

顺序一致性模型中的每个操作必须立即对任意线程可见。

JMM中就没有这个保证。未同步程序在JMM中不但整体的执行顺序是无序的,而且所有线程看到的操作执行顺序也可能不一致

  • 在当前线程把写过的数据缓存在本地内存中,没有刷新到主内存之前,这个写操作仅对当前线程可见;从其他线程的角度来看,会认为这个写操作根本没有被当前线程执行。
  • 只有当前线程把本地内存中写过的数据刷新到主内存之后,这个写操作才能对其他线程可见。

这种情况下,当前线程和其他线程看到底操作顺序将不一致。

同步程序的顺序一致性效果

顺序一致性模型中,所有操作完全按程序的顺序串行执行

JMM中,临界区内的代码可以重排序(但JMM不允许临界区内的代码“逸出”到临界区之外,那会破坏监视器的语义)。JMM会在退出临界区和进入临界区这两个关键时间点做一些特别处理,使得线程在这两个时间点具有与顺序一致性模型相同的内存视图

监视器具有互斥执行的特性。

JMM在具体实现上的基本方针为;在不改变(正确同步的)程序执行结果的前提下,尽可能的为编辑器和处理器的优化大开方便之门。

未同步程序的执行特性

对于未同步或为正确同步的多线程程序,JMM只提供最小安全性:线程执行时读取到的值,是之前某个线程写入的值或默认值(0,Null,False),JMM保证线程读操作取到的值不会是无中生有的

为实现最小安全性,JVM在堆上分配对象时,首先会对内存空间进行清零,然后才会在上面分配对象(JVM内部会同步这两个操作)。因此,清零的内存空间(Pre-zeroed Memory)分配对象时,域的默认初始化已经完成

未同步程序在JMM中的执行,整体上是无序的,其执行结果无法预知,不保证执行结果与该程序在顺序一致性模型中的执行结果一致。

未同步程序在两个模型中执行特性的几个差异:

顺序一致性模型

JMM

单线程内的操作会按照程序的顺序执行。

保证

不保证(如临界区内的重排序)

所有线程能看到一致的操作执行顺序。

保证

不保证

对所有的内存读/写操作都具有原子性。

保证

JMM不保证对64位的long型和double型变量的写操作具有原子性。

最后一个差异与处理器总线的工作机制密切相关。

在计算机中,数据通过总线在处理器和内存之间传递。

每次处理器和内存之间的数据传递都是通过一系列步骤来完成的,这一系列步骤称为总线事务(Bus Transaction)。

总线事务包括读事务(Read Transaction)和写事务(Write Transaction).

  • 读事务从内存传递数据到处理器;
  • 写事务从处理器传递数据到内存;
  • 每个事务会读/写内存中一个或多个物理上连续的字。

总线会同步试图并发使用总线的事务

在一个处理器执行总线事务期间,总线会禁止其他的处理器和I/O设备执行内存的读/写。

当多个处理器同时向总线发起总线事务,这时总线仲裁(Bus Arbitration)会对竞争作出裁决。

总线仲裁会确保所有处理器都能公平的访问内存。

总线的这些工作机制可以把所有处理器对内存的访问以串行化的方式来进行。在任意时间点,最多只能有一个处理器可以访问内存。这个特性确保了单个总线事务之中的内存读/写操作具有原子性

在一些32位的处理器上,如果要求对64位数据的写操作具有原子性,会有比较大的开销。

为照顾这中处理器,Java语言规范鼓励但不强求JVM对64位的long型变量和double型变量的写操作具有原子性。

当JVM在这种处理器上运行时,可能会把一个64位long/double型变量的写操作拆分成两个32位的写操作来执行。这两个32位的写操作可能会被分配到不同的总线事务中执行,此时对这个64位变量的写操作将不具有原子性

在JSR-133之前的旧内存模型中,一个64位long/double型变量的读/写操作可以被拆分成两个32位的读/写操作来执行。

JSR-133内存模型开始(即JDK5开始),仅仅只允许把一个64位long/double型变量的写操作拆分成两个32位的写操作来执行,任意读操作在JSR-133中都必须具有原子性(即任意读操作必须要在单个读事务中执行)。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入理解Java内存模型(三)——顺序一致性
数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争。java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序。 当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果(前一章的示例正是如此)。如果一个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序。 JMM对正确同步的多线程程序的内存一致性做了如下保证: 如果程序是正确同步的,程序的执行将具有顺序一致性(sequentially consistent)–即程序的执行
小小明童鞋
2018/06/13
1.2K0
Java并发编程(四)Java内存模型
相关文章 Java并发编程(一)线程定义、状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 前言 此前我们讲到了线程、同步以及volatile关键字,对于Java的并发编程我们有必要了解下Java的内存模型,因为Java线程之间的通信对于工程师来言是完全透明的,内存可见性问题很容易使工程师们觉得困惑,这篇文章我们来主要的讲下Java内存模型的相关概念。 1.共享内存和消息传递 线程之间的通信机制有两种:共享内存和消息传递;在共享内存的并发模型里,线程之间共享程序的公共状
用户1269200
2018/02/01
7670
Java并发编程(四)Java内存模型
一文搞懂什么是JMM重排序、内存屏障、顺序一致性
在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。
鲁大猿
2024/01/14
8030
一文搞懂什么是JMM重排序、内存屏障、顺序一致性
​带你深入理解Java内存模型JMM
在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。
Java技术江湖
2019/09/25
4540
《深入理解 Java 内存模型》读书笔记(干货,万字长文)
《深入理解 Java 内存模型》 程晓明著,该书在以前看过一遍,现在学的东西越多,感觉那块越重要,于是又再细看一遍,于是便有了下面的读书笔记总结。全书页数虽不多,内容讲得挺深的。细看的话,也是挺花时间的,看完收获绝对挺大的。也建议 Java 开发者都去看看。里面主要有 Java 内存模型的基础、重排序、顺序一致性、Volatile 关键字、锁、final。本文参考书中内容。
芋道源码
2018/10/26
5210
JMM—详细总结
Java并发的通信机制是通过共享内存实现的。线程之间共享程序的公共状态,线程通过读写内存中的公共状态进行隐式通讯。这对程序员是透明的,我们需要理解其工作机制,以防止内存可见性问题,从而编写出正确同步的代码。
用户5325874
2020/01/16
7500
JMM—详细总结
3分钟速读原著《Java并发编程的艺术》(一)
总纲介绍: 1.并发编程会遇到的问题以及解决方案 2.Java并发编程的底层实现原理,CPU和JVM是如何帮助解决的 3.Java内存模型,java线程之间的通信 4.多线程技术带来的好处,多线程的生命周期的基本概念 5.Java并发包和锁相关的API和组件,以及这些API和组件的使用方式和实现细节 6.并发容器的实现原理 7.Java中的原子类操作 8.并发工具类 9.线程池的实现原理和使用建议 10.Executor框架和整体结构和成员组件 11.并发编程的实现 第一章 上下文切换:CPU通过实践片
cwl_java
2019/10/26
5680
万丈高楼平地起—Java并发的基石JMM(Java内存模型)
顺序一致性模型可以保证并发编程的特性不被破坏,为多线程程序提供了极强的 内存一致性保证
淇妙小屋
2022/03/30
2700
万丈高楼平地起—Java并发的基石JMM(Java内存模型)
你知道Java并发三大问题么,volatile和CAS又是什么?
如果是在一个串行执行的语言中,执行SetCheck类中的check方法永远不会返回false,即使编译器,运行时和计算机硬件并没有按照你所期望的逻辑来处理这段程序,该方法依然不会返回false。在程序执行过程中,下面这些你所不能预料的行为都是可能发生的:
Java技术江湖
2019/09/25
5260
读书笔记《Java并发编程的艺术 - 方腾飞》- Java内存模型
而我们这里要记录的则是 Java 线程间通信使用的 共享内存, 也就是 Java 的内存是怎么样子的
星尘的一个朋友
2020/11/25
6440
并发编程系列之线程并行学习笔记
同步和异步的本质区别是是否需要等待,比如一个方法在执行,必须等前面一个方法程执行完成,才可以执行,这就是同步。如果不需要等上一个方法执行完成,并行或者并发执行,这就是异步调用。
SmileNicky
2022/05/07
3120
JMM1、基础与概念2、重排序6、锁7、java concurrent包的通用化的实现模式7、final8、双重检查和延迟优化
1、基础与概念 (1)、共享性、互斥性、原子性、可见性、有序性。 (2)、JMM内存模型——描述线程本地内存和主内存之间的抽象关系。线程A和线程B之间通讯,需要通过主内存。 JMM属于语言级的内存模型
JavaEdge
2018/05/16
7220
深入理解Java内存模型(四)——volatile
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别。理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明,请看下面的示例代码: class VolatileFeaturesExample { //使用volatile声明64位的long型变量 volatile long vl = 0L; public void set(long l) {
小小明童鞋
2018/06/13
6160
volatile synchronized cas
之前写了《熔断》,以及其中使用的《计数器算法》;本来是要接着再写不通过定时器清理计数环的计数器算法,看了下我司亿级网关的计数器,百行的代码,但却是满满bug。不得穿插一下并发的基础知识
码农戏码
2021/03/23
5950
线程并行学习笔记
同步和异步的本质区别是是否需要等待,比如一个方法在执行,必须等前面一个方法程执行完成,才可以执行,这就是同步。如果不需要等上一个方法执行完成,并行或者并发执行,这就是异步调用。
SmileNicky
2019/01/17
4330
【Java】【并发编程】详解Java内存模型
Java内存模型即 Java Menory Model,简称JMM。JMM定义了Java虚拟机(JVM)在计算机内存(RAM)中的工作方法。JVM是整个计算机虚拟模型,所以JMM隶属于JVM的。
玖柒的小窝
2021/09/24
2.1K0
【Java】【并发编程】详解Java内存模型
彻底理解Java并发:volatile关键字
Java 中的 volatile 关键字,用来修饰会被不同线程访问和修改的变量,通常用于并发编程中,是 Java 虚拟机提供的轻量化同步机制。
栗筝i
2022/12/01
5250
彻底理解Java并发:volatile关键字
嘿,你要的Java内存模型(JMM)来了!
在单核计算机中,计算机中的CPU计算速度是非常快的,但是与计算机中的其它硬件(如IO、内存等)同CPU的速度比起来是相差甚远的,所以协调CPU和各个硬件之间的速度差异是非常重要的,要不然CPU就一直在等待,浪费资源。单核尚且如此,在多核中,这样的问题会更加的突出。硬件结构如下图所示:
Simon郎
2021/02/06
7420
Java内存模型
在Java中,所有 实例域、静态域 和 数组元素 都储存在堆内存中,堆内存在线程之前共享。 本文用 共享变量 统一描述 实例域、静态域 和 数组元素 。
103style
2022/12/19
3600
Java内存模型
Java内存模型(Java Memory Model,JMM)
多线程、高并发问题相信是每一位从事Java研发工作的程序员都不可回避的一个重要话题。从启动一个线程,到使用volatile、synchronized、final关键字,到使用wait()、notify()、notifyAll()、join()方法,再到编写复杂的多线程程序,不知道大家有没有思考过这样一个问题,为什么要使用这些API,或者说这些API到底给编程人员提供了什么样的保证,才使得在多线程环境下程序的运行结果能够符合预期。它就是Java Memory Model(后续简称JMM)。本文就带领大家一起,绕道这些API的背后,一探究竟。
京东技术
2021/11/25
9050
Java内存模型(Java Memory Model,JMM)
相关推荐
深入理解Java内存模型(三)——顺序一致性
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档