Java并发和多线程编程学习(二) Java内存模型

news2024/11/25 14:36:16
  • 并发编程中需要处理的两个重要问题是线程之间如何通信以及线程之间如何同步,Java的并发采用的是共享内存模型,且线程之间的通信总是隐式执行,所以需要我们深入学习从而避免复杂的内存可见性问题

内存模型的抽象结构

  • 在Java中,所有实例域、静态域和数组元素都存储在堆内存中,堆内存在线程之间共享,这些数据受到内存模型的影响
  • Java线程之间的通信受到内存模型(JMM)控制,JMM决定一个线程对共享变量的写入另一个线程何时可见
  • 从抽象的角度看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存(这是一个抽象概念,实际不存在),本地内存中存储了该线程以读/写共享变量的副本
    在这里插入图片描述
  • 如上图,如果A要和B进行线程通信,首先线程A要把本地内存A中更新过的共享变量刷新到主内存中,然后线程B再到主内存中读取已更新过的共享变量

指令重排序

  • 编译器优化的重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序
  • 指令集并行的重排序:现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
  • 内存系统的重排序:由于处理器使用缓存和读/写缓冲区,使得加载和存储操作可能看上去可能是在乱序执行

上述后两个属于处理器重排序,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障指令来禁止特定类型的处理器重排序

load和store是两种原子操作(JVM一共规定了8种,可以了解一下),分别表示将工作内存中的变量刷新到副本中和将工作内存中的变量的值传到主内存中,有 s t o r e s t o r e , s t o r e l o a d , l o a d s t o r e , l o a d l o a d storestore,storeload,loadstore,loadload storestore,storeload,loadstore,loadload四种内存屏障,其中 s t o r e l o a d storeload storeload是一个全能型屏障,一般的多处理器都支持这个屏障,它的含义是在这个内存屏障之前的store和之后的load指令不能重排序

happens-before

  • 如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在 h a p p e n s − b e f o r e happens-before happensbefore关系

与程序员密切相关的重要规则如下

  1. 程序顺序规则:一个线程中的每个操作happens-before于该线程中的任意后续操作
  2. 监视器锁规则:对一个锁的解锁happens-before于随后对这个锁的加锁
  3. volatile变量规则:对一个volatile域的写happens-before于任意后续对这个volatile域的读
  4. 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C
  5. start()规则:如果线程A执行操作ThreadB.start(),那么A线程中的ThreadB.start()操作happens-before于线程B中的任意操作
  6. join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从TheadB.join()操作成功返回

注意这个规则仅仅要求前一个操作对后一个操作可见,没有执行上的先后顺序

数据依赖性

  • 如果两个操作之间存在数据依赖,那么指令重排不会改变这个两个操作之间的排列顺序

as-if-serial

  • 意思是不管怎么排序,程序的执行结果不能被改变

volatile的内存语义

  • 线程A写一个volatile变量,实质上是A向接下来将要读这个volatile变量的某个线程发出了作出修改的消息
  • 线程B读一个volatile变量,实质上是B接收了之前某个线程发出的修改消息
  • 线程A写后线程B读一个volatile变量实质上是A通过主内存向B发送消息

实现

  • JMM采用保守策略,注意只要是它加的就没有多余的
  • 在一个 v o l a t i l e volatile volatile写操作前面加一个 s t o r e s t o r e storestore storestore屏障;在后面加一个 s t o r e l o a d storeload storeload屏障
  • 在一个 v o l a t i l e volatile volatile读操作后面加一个 l o a d l o a d loadload loadload屏障,这个主要是防止 v o l a t i l e volatile volatile读和普通读指令重排,注意volatile读的时候会刷新本地内存的所有共享变量;在后面加一个 l o a d s t o r e loadstore loadstore屏障

锁释放和获取的内存语义和 v o l a t i l e volatile volatile的写和读有相同的内存语义

final域的内存语义

final域的重排序规则

我们知道,新版本的Java的final对象是线程安全的,那么它是如何实现的呢?主要是应用到了写和读final域的重排序规则,具体如下

  • 写final域的重排序规则:在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。这可以保证对象引用为任意线程可见之前,final域已经被正确初始化过了
  • 读final域的重排序规则:初次读一个包含final域的对象的引用与随后初次读这个final域,这两个操作之间不能重排序,这主要是保证final域一定会被初始化,只要引用不为null,则final域一定被初始化了

final域语义的处理器实现

  • 写final域的重排序规则要求编译器在final域的写之后,构造函数return之前插入一个 s t o r e s t o r e storestore storestore屏障
  • 读final域的重排序规则要求编译器在final域的读前面插入一个 l o a d l o a d loadload loadload屏障

由于x86处理器的性质,在这个处理器中,final域读写不会插入任何内存屏障

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

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

相关文章

java计算机毕业设计ssm基于H5的音乐播放管理系统

项目介绍 该系统是基于H5,使用Vue、JavaScript、CSS技术开发而成。系统服务器使用Tomcat,利用MySQL存储数据、用JDBC实现数据的访问。管理员在系统部署阶段将所有用户对应权限进行分配。正式投入使用时,用户通过登录模块进入系统。根据权限控制管理,每个用户角色的操作界面也有…

【轻量级开源ROS 的机器人设备(4)】--(2)通信实现

前文链接 【轻量级开源ROS 的机器人设备(4)】--(1)通信模块_无水先生的博客-CSDN博客 三、 通信概要 概述 ROS 的通信层是 ros_comm 堆栈的一部分,遵循发布/订阅范式,如图 2.2 所示。网络,也称…

(设计模式) (李建忠 C++) 23种设计模式

文章目录前言组件协作模板方法 Template Method动机模式定义结构代码情景版本1版本2变化原理要点总结个人小结策略模式 Strategy动机模式定义结构代码情景版本1版本2要点总结个人小结观察者模式 Observer动机模式定义结构代码场景版本1版本2版本2要点总结个人小结单一职责装饰模…

斐波那契问题——上台阶问题

题目: 给定整数N,代表台阶数,一次可以跨2个或者1个台阶,返回有多少种走法。 举例: N3,可以三次跨一个台阶,也可以先跨2再跨1,也可以先跨1再跨2,共三种走法。 思路&…

上海还有哪些比较好的IB学校?

今天我们就一起来盘点沪上几所办学成绩比较好的IB学校,快来看看哪所学校才是孩子的最好选择! Promise 上海民办平和学校 上海市民办平和学校(Shanghai Pinghe School)是由上海金桥(集团)有限公司于1996年9月…

常用Java接单平台一览

不少主攻Java的程序员兄弟除了工作,还会在空闲时间选择接单来增加自己的收入;对于那些生活在二三线的程序员兄弟们,通过接单,来获得与一线城市对等的收入。具体该怎么做,且听我娓娓道来。接下来干货满满,先…

前端—新增的嵌入多媒体元素与交互性元素

新增的嵌入多媒体元素与交互性元素 新增的嵌入多媒体元素有video和audio元素,分别是用来插入视频和声音的。值得注意的是,可以在开始标签和结束标签之间放置文本内容,这样旧版本的浏览器就可以显示出不支持该标签的信息。例如下面的代码。HT…

Qt Visual Studio添加Qt ui和编译注意事项

文章目录背景新建Widget 对象UIC程序生成ui_xxxx.h文件编译出错设置QtWidgetsTestClass.h的属性总结背景 工程中需要新的界面VS中新建Qt的ui文件,然后需要生成对应的.cpp 和 .h 文件 新建Widget 对象 生成对应的三个文件.ui, xxx. cpp, xxx.h 但是此时在QtWidget…

IDEA报错问题:If you already have a 64-bit JDK installed 解决方法【杭州多测师_王sir】【杭州多测师】...

启动IDEA的时候突然报错: 第一步:首先进入到C:\Users\用户名\.IdeaIC2019.3\config这个目录下面找到idea64.exe.vmoptions文件 第二步:通过notepad打开,进入编辑 第三步:然后修改配置如下:把Xms和Xmx的参数…

[MySQL]-主从同步实战

[MySQL]-主从同步实战 森格 | 2022年12月14日 本文主要为在平时work中遇到的主从同步上的问题的处理,对其进行巩固总结。 一、场景介绍 ​ 在一个风和日丽的下午4点半,突然就收到一个主从同步失败的提示,三两下打开从库一看,好嘛…

Stimulsoft Reports 2023.1.1 Crack 根据自身需求选择

Stimulsoft 专门从事 Microsoft .NET Framework 组件的开发。客户满意是公司的首要任务,因此它旨在生产顶级质量的软件。应用程序开发并不总是那么容易,但 Stimulsoft 尽最大努力帮助开发人员将当今市场上最先进的技术整合到他们的应用程序中 特征 Razor…

老照片修复怎么修?这三个方法可以让你实现修复操作

相信大家在家里翻看以前的照片时,会发现有部分照片颜色已经泛黄,内容也跟着变得有些模糊不清了,那当我们遇到这种情况的时候,应该怎么办呢?别担心,今天就来教大家几个实用的方法,让大家学会老照…

stm32 adc dma

ADC采集电压,使用DMA传输到内存 一,ADC设置 1,Mode。 这里我们使用ADC的独立模式。 2,时钟分频 ADCCLK由 PCLK2分频得到,最大时钟频率36M。ADC 时钟太快,采样可能不够准确,误差大。 3,采样分…

砥砺深耕,笃行致远向未来——中国社科院与美国杜兰金融管理硕士项目

想在一个领域里有所发展,相信深耕下去一定会有收获。工作中积累的实战经验或是在文章上看到的补给型知识大都属于碎片化的,系统的学习理论知识很重要,尤其对于金融行业,中国社科院与美国杜兰大学合办金融管理硕士项目的出现&#…

演讲实录|OpenMLDB 与阿里云 MaxCompute 生态集成

在 OpenMLDB 第 8 期 Meetup 中,OpenMLDB PMC 陈迪豪以出租车行车时间预测问题为例,使用 OpenMLDB 基于阿里云 MaxCompute 的 Serverless 服务搭建机器学习应用,从数据引入开始,实现了端到端的机器学习应用全流程构建。 云服务作…

软件工程---习题五

1.为每种类型的模块耦合举一个具体例子。   答:耦合式对一个软件结构内不同模块之间互联程度的度量。耦合强弱取决于接口的复杂度,进入或访问某一模块的点,以及通过接口的数据。一般模块之间的可能的连接方式有七种,构成耦合的七…

深入MVC模式和三层架构

MVC模式 MVC 是一种分层开发的模式,其中: M:Model,业务模型,处理业务 V:View,视图,界面展示 C:Controller,控制器,处理请求,调用模…

深度学习中的卷积操作

本文从信号处理中的互相关运算引入深度学习中的卷积。 然后介绍了不同的卷积类型,以及如何在pytorch中使用这些卷积层。 (在看pytorch文档中的Conv1D/2D/3D的时候感到比较困惑,又很好奇深度学习中各种各样的卷积操作。于是结合整理几乎包含深…

Linux软硬链接与动静态库

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸 文章目录一、创建软硬链接二、软硬链接①软链接②硬链接③硬链接的用处④软硬链接的区别三、库的作用①库与为什么用库②动静态库的加载过程四、动静…

大数据分析如何进行日志采集

最近经常和技术大牛在交流,每次的碰撞都会让我产生更多的想法。例如这次谈到的,某企业信息化用了二三十种的公有云服务、有二十多种业务系统的数据库使用了同一个物理库、云产品的稳定性是值得肯定的。今天我们就来谈一谈日志在数据库中的作用以及如何采…