广告
返回顶部
首页 > 资讯 > 后端开发 > Python >并发编程之Java内存模型顺序一致性
  • 251
分享到

并发编程之Java内存模型顺序一致性

2024-04-02 19:04:59 251人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录1、数据竞争和顺序一致性1.1 Java内存模型规范对数据竞争的定义1.2 JMM对多线程程序的内存一致性做的保证2、顺序一致性内存模型2.1 特性2.2 举例说明顺序一致性模型

简介:

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

1、数据竞争和顺序一致性

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

1.1 Java内存模型规范对数据竞争的定义

定义如下:

  • 在一个线程中写一个变量
  • 在另一个线程中读同一个变量
  • 写和读没有通过同步来排序

如果一个多线程程序能够正确同步,这个程序将是一个没有数据竞争的程序,往往存在数据竞争的程序,运行结果与我们的预期结果都会存在偏差。

1.2 JMM对多线程程序的内存一致性做的保证

如果程序正确同步(正确使用synchronizedvolatilefinal),程序的执行将具有顺序一致性(Sequentially Consistent)——即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同。

2、顺序一致性内存模型

2.1 特性

  • 一个线程中的所有操作必须按照程序的执行顺序来执行
  • (不管是否正确同步)所有的线程都只能看到一个单一的操作执行顺序,每个操作都必须原子执行且立刻对所有线程可见。

图示:顺序一致性内存模型视图

在概念上,顺序一致性模型有一个单一的全局内存,这个内存通过一个左右摆动的开关可以连接到任意一个线程,同时每一个线程必须按照程序的顺序来执行内存的读/写操作。上图中可以看出,在任意时刻最多只有一个线程可以连接到内存。因此,在多线程并发执行时,图中的开关装置能把所有的内存读/写操作串行化(即在顺序一致性模型中所有操作之间具有全序关系)。

2.2 举例说明顺序一致性模型

假设两个线程A和B并发执行。其中

A线程的操作在程序中的顺序为:A1 - A2 - A3

B线程的操作在程序中的顺序为:B1 - B2 - B3

假设线程A和线程B使用监视器来正确同步,A线程的3个操作执行后释放监视器锁,随后B线程获取同一个监视器锁。那么程序在顺序一致性模型中的执行效果如下所示:顺序一致性模型的一种执行效果

假设线程A和线程B没有做同步,那么这个未同步的程序在顺序一致性模型中的另一种可能的效果如下所示:

顺序一致性模型的另一种执行效果:

未同步程序在顺序一致性模型中虽然整体执行顺序是无序的,但是所有线程都只能看到一个一直的整体执行顺序。以上图为例,线程A和B看到的执行顺序都是:A1 - B1 - A2 - B2 - A3 - B3。之所以能得到这个保证是因为顺序一致性内存模型中的每个操作必须立即对任意线程可见。

但是,在JMM中就没有这个保证。未同步程序在JMM中不但整体的执行顺序是无序的,而且所有线程看到的操作执行顺序也可能不一致。 比如,在当前线程把写过的数据缓存在本地内存中,在没有刷新到主内存之前,这个写操作仅对当前线程可见;从其他线程的角度来观察,会认为这个写操作根本被当前线程执行。只有当前线程把本地内存中写过的数据刷新到主内存之后,这个写操作才能对其他线程可见。这种情况就会出现多种运行结果。

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

对上一章的ReorderExample程序用锁来同步


package com.lizba.p1;


public class SynReorderExample {

    // 定义变量a
    int a = 0;
    // flag变量是个标记,用来标志变量a是否被写入
    boolean flag = false;

    public synchronized void writer() {     // 获取锁
        a = 1;
        flag = true;
    }                                       // 释放锁

    public synchronized void reader() {     // 获取锁
        if (flag) {
            int i = a * a;
            System.out.println("i:" + i);
        }
    }                                       // 释放锁

}

测试代码



public static void main(String[] args) {

    final SynReorderExample re = new SynReorderExample();

    new Thread() {
        public void run() {
            re.writer();
        }
    }.start();

    new Thread() {
        public void run() {
            re.reader();
        }
    }.start();
}

执行多次结果结果都为1

总结:

在上面的示例代码中,假设A线程执行writer()方法后,B线程执行reader()方法。这是一个正确同步的多线程程序。根据JMM规范,该程序的执行结果将与该程序在顺序一致性内存模型中的执行结果相同。

顺序一致性模型中和JMM内存模型中的执行时序图

总结

在顺序一致性模型中,所有操作完全按程序的顺序串行执行。而在JMM中,临界区内的代码可以重排序(但JMM不允许临界区的代码“逸出”到临界区之外,那样会破坏监视器锁的语义)。JMM会在进入临界区和退出临界区的关键时间点做一些特殊处理,使得线程在这两个时间点具有顺序一致性模型中相同的内存视图。虽然线程A在临界区内做了重排序,但由于监视锁互斥执行的特性,这里线程B无法“观察”到线程A在临界区内的重排序。JMM在具体实现上的基本方针为:在不改变(正确同步)程序执行结果的前提下,尽可能为编译器和处理器的优化打开方便大门。

2.4 未同步程序的执行特性

对于未同步或者未正确同步(代码写错了的兄弟们),JMM只提供最小的安全性:

线程执行时读取到的值不会无中生有(Out Of Thin Air)

  • 之前某个线程写入的值
  • 默认值(0、Null、False)-- JVM会在已经清零了内存空间(Pre-zeroed Memory)分配对象。

未同步程序在两个模型中的执行特性对比

比较内容\模型名称 顺序一致性模型 JMM模型
单线程内顺序执行 ×
一致的操作执行顺序 ×
64位long型和double型变量写原子性 ×

第三个差异和总线的机制有关。在一些32位处理器上,处理64位的数据写操作,需要将一个写操作拆分为两个32位的写操作。

3、 64位long型和double型变量写原子性

3.1 CPU、内存和总线简述

在计算机中,数据通过总线在处理器和内存之间传递,每次处理器和内存之间的数据传递都是通过一系列的步骤来完成的,这一系列的步骤称之为总线事务Bus Transaction)。总线事务包括读事务(Read Transaction)和写事务(WriteTransaction),事务会读\写内存中一个或多个物理上连续的字。

  • 读事务 → 内存到处理器
  • 写事务 → 处理器到内存

重点:总线会同步试图并发使用总线的事务。在一个处理器执行总线事务期间,总线会禁止其他处理器和I\O设备执行内存的读\写。

图示:总线工作机制

由上图所示:设处理器A、B、C、D同时向总线发起总线事务,这时总线总裁(Bus Arbitration)会对竞争作出裁决,这里假设处理器A在竞争中获胜(总线仲裁会确保所有处理器能公平访问内存)。此时处理器A继续它的总线事务,而其他所有的总线事务必须要等待A的事务完成才能再次执行内存的读\写操作。总线事务工作机制确保处理器对内存的访问以串行的方式执行。在任意时间点都只有一个处理器可以访问内存,这个特性能确保总线事务之间的内存读\写操作具有原子性。

3.2 long和double类型的操作

在一些32位的处理器上,如果要求对64位数据的写操作具有原子性,那么会有非常大的同步开销。Java语言规范中鼓励但不强求JVM对64位long型和double类型的变量写操作具有原子性。当JVM在这种处理器上运行时,会把一个64位的变量写操作拆成两个32位写操作来执行,此时写不具备原子性。

图示:总线事务执行的时序图

存在问题:

假设处理器A写一个long类型的变量,同时处理器B要读这个long类型的变量。处理器A中64位的写操作被拆分成两个32位的写操作,且这两个32位的写操作被分配到不同的事务中执行。此时,处理器B中64位的读操作被分配到单个读事务中执行。如果按照上面的执行顺序,那么处理器B读取的将会是一个不完整的无效值。

处理方式:

jsR-133内存模型开始(jdk1.5),写操作能拆分成两个32位写事务执行,读操作必须在单个事务中执行。

到此这篇关于并发编程之Java内存模型顺序一致性的文章就介绍到这了,更多相关Java内存模型顺序一致性内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 并发编程之Java内存模型顺序一致性

本文链接: https://www.lsjlt.com/news/156375.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 并发编程之Java内存模型顺序一致性
    目录1、数据竞争和顺序一致性1.1 Java内存模型规范对数据竞争的定义1.2 JMM对多线程程序的内存一致性做的保证2、顺序一致性内存模型2.1 特性2.2 举例说明顺序一致性模型...
    99+
    2022-11-12
  • Java内存模型顺序一致性的示例分析
    小编给大家分享一下Java内存模型顺序一致性的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!简介:顺序一致性内存模型是一个理论参考模型,处理器的内存模型和...
    99+
    2023-06-25
  • 并发编程之Java内存模型
    目录一、Java内存模型的基础1.1 并发编程模型的两个关键问题1.2 Java内存模型的抽象结构1.3 从源代码到指令重排序1.4 写缓冲区和内存屏障1.4.1 写缓冲区1.4.2...
    99+
    2022-11-12
  • Java并发编程之Java内存模型
    目录1、什么是Java的内存模型2、为什么需要Java内存模型3、Java内存模型及操作规范4、Java内存模型规定的原子操作5、Java内存模型同步协议6、Java内存模型的HB法...
    99+
    2022-11-12
  • 并发编程之Java内存模型锁的内存语义
    目录1、锁的释放-获取建立的happens-before关系2、锁释放和获取的内存语义3、锁内存的语义实现4、concurrent包的实现简介: 锁的作用是让临界区互斥执行。本文阐述...
    99+
    2022-11-12
  • 并发编程之Java内存模型volatile的内存语义
    1、volatile的特性 理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是使用同一个锁对单个读/写操作做了同步。 代码示例: package ...
    99+
    2022-11-12
  • 怎么深入理解Java多线程与并发框中的顺序一致性模型
    怎么深入理解Java多线程与并发框中的顺序一致性模型,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、竞态条件(Race Condition)计算的正确性取决于 多个线程 执行...
    99+
    2023-06-05
  • Java并发编程之volatile与JMM多线程内存模型
    目录一、通过程序看现象二、为什么会产生这种现象(JMM模型)?三、MESI 缓存一致性协议 一、通过程序看现象 在开始为大家讲解Java 多线程缓存模型之前,我们先看下面的这一段代码...
    99+
    2022-11-13
  • Java并发编程中的内存模型是什么
    这篇文章主要介绍“Java并发编程中的内存模型是什么”,在日常操作中,相信很多人在Java并发编程中的内存模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发编程中的内存模型是什么”的疑惑有所...
    99+
    2023-06-25
  • Java并发编程之volatile与JMM多线程内存模型实例分析
    本篇内容主要讲解“Java并发编程之volatile与JMM多线程内存模型实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发编程之volatile与JMM多线程内存模型实例分析”...
    99+
    2023-06-30
  • 怎么浅谈Java并发编程中的Java内存模型
    这篇文章的内容主要围绕怎么浅谈Java并发编程中的Java内存模型进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!物理计算机并发问题在介绍Java内存...
    99+
    2023-06-17
  • Java并发编程数据库与缓存数据一致性方案解析
    目录一、序言二、不同的声音1、操作的先后顺序2、处理缓存的态度三、线程并发分析查询数据1、非并发环境2、并发环境更新数据1、非并发环境2、并发环境依赖环境四、先数据库后缓存数据一致性...
    99+
    2022-11-13
  • 深入理解Java多线程与并发框(第③篇)——Java内存模型与原子性、可见性、有序性
    一、Java内存模型Java Memory Modle,简称 JMM,中文名称 Java内存模型,它是一个抽象的概念,用来描述或者规范访问内存变量的方式。因为各中计算机的操作系统和硬件不同,方式机制也可能不同,Java内存模型用于屏蔽(适配...
    99+
    2023-06-05
  • Java并发编程数据库与缓存数据一致性方案是什么
    本文小编为大家详细介绍“Java并发编程数据库与缓存数据一致性方案是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java并发编程数据库与缓存数据一致性方案是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作