原文网址:Java多线程--内存模型(JMM)--详解_IT利刃出鞘的博客-CSDN博客

简介

本文介绍Java的内存模型(JMM)。包括:JMM是什么,JMM结构,JMM的特性(线程安全型体现在哪些方面),synchronized的作用,volatile的作用。

JMM是什么

JMM即为JAVA 内存模型(java memory model)。因为在不同的硬件生产商和不同的操作系统下,内存的访问逻辑有一定的差异,结果就是当你的代码在某个系统环境下运行良好,并且线程安全,但是换了个系统就出现各种问题。Java内存模型,就是为了屏蔽系统和硬件的差异,让一套代码在不同平台下能到达相同的访问结果。JMM从java 5开始的JSR-133发布后,已经成熟和完善起来。

内存模型描述了程序中各个变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节

Java Memory Model(Java内存模型), 围绕着在并发过程中如何处理可见性、原子性、有序性这三个特性而建立的模型。

JMM规定

  • 所有的变量都存储在主内存(Main Memory)中。
  • 每个线程有自己的工作内存(Working Memory),线程的工作内存中保存了该线程使用到的变量的主内存的副本拷贝,
  • 线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量(首先要将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后在将变量写回主内存)。(volatile变量仍然有工作内存的拷贝,但是由于它特殊的操作顺序性规定,所以看起来如同直接在主内存中读写访问一般)。
  • 不同的线程之间无法直接访问对方工作内存中的变量,线程之间值的传递都需要通过主内存来完成。

JMM结构

线程A与线程B之间如要通信的话,必须要经历下面2个步骤:

  1. 线程A把本地内存A中更新过的共享变量刷新到主内存中去。
  2. 线程B到主内存中去读取线程A之前已更新过的共享变量。

JMM三个特性

JMM三个特性(线程安全性体现方面)

线程的安全性问题体现在:原子性、可见性、有序性。

体现方面

说明

导致原因

解决方法

原子性

一个或者多个操作在CPU执行的过程中不被中断的特性

线程切换

synchronized

LOCK

JDK Atomic开头的原子类(非阻塞CAS算法)

可见性

一个线程对共享变量的修改,另外一个线程能够立刻看到

缓存

synchronized

LOCK

volatile

有序性

程序执行的顺序按照代码的先后顺序执行

编译优化

Happens-Before规则

Happens-Before规则

参考网址:java内存模型以及happens-before规则 - 简书

1.规则项

规则

说明

程序顺序规则 一个线程中的每个操作,happens-before于该线程中的任意后续操作
监视器锁规则 对一个锁的解锁,happens-before于随后对这个锁的加锁。

volatile变量规则

对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
传递性规则 如果A happens-before B,且B happens-before C,那么A happens-before C。
start()规则 如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
join()规则 如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

线程中断规则

对线程interrupt()的调用 happen—before 发生于被中断线程的代码检测到中断时事件的发生。

对象终结规则

就是一个对象的初始化的完成(构造函数执行的结束) happens-before它的finalize()方法

2. happens-before含义

JMM(java 内存模型)可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。具体的定义为:

(1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

(2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么这种重排序并不非法(也就是说,JMM允许这种重排序)。

上面的(1)是JMM对程序员的承诺。从程序员的角度来说,可以这样理解happens-before关系:如果A happens-before B,那么Java内存模型将向程序员保证——A操作的结果将对B可见,且A的执行顺序排在B之前。注意,这只是Java内存模型向程序员做出的保证!

上面的(2)是JMM对编译器和处理器重排序的约束原则。正如前面所言,JMM其实是在遵循一个基本原则:只要不改变程序的执行结果(指的是单线程程序和正确同步的多线程程序),编译器和处理器怎么优化都行。JMM这么做的原因是:程序员对于这两个操作是否真的被重排序并不关心,程序员关心的是程序执行时的语义不能被改变(即执行结果不能被改变)。因此,happens-before关系本质上和as-if-serial语义是一回事。

3.happens-before存在的意义

重排序原则有编译器重排序和处理器重排序等,如果让程序员再去了解这些底层的实现以及具体规则,那么程序员的负担就太重了,严重影响了并发编程的效率。因此,JMM为程序员在上层提供了六条规则,这样我们就可以根据规则去推论跨线程的内存可见性问题,而不用再去理解底层重排序的规则。

synchronized作用

说明

synchronized可保证原子性、有序性和可见性

一个线程执行互斥代码过程

1. 获得同步锁;
2. 清空工作内存;
3. 从主内存拷贝对象副本到工作内存;
4. 执行代码(计算或者输出等);
5. 刷新主内存数据;
6. 释放同步锁。

volatile作用

说明

保证有序性和可见性,不保证原子性。

  • 可见性

    • 一个变量被声明为volatile时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存。当其他线程读取该共享变量时,会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值。
  • 有序性
    • 通过禁止指令重排的方式保证有序性。

volatile流程

1)从主存读取volatile变量到本地副本
2)修改变量值
3)本地副本值写回主存
4)插入内存屏障,即lock指令。内存屏障会让其他线程每次读取强制从主存读取(让其他线程可见)

可见volatile并没有加锁,1234不是原子性的。

其他网址

JMM概述_牧竹子-CSDN博客_jmm

java内存模型JMM理解整理 - 阿姆斯特朗回旋炮 - 博客园

java 程序中怎么保证多线程的运行安全

Java多线程--内存模型(JMM)--详解相关推荐

  1. Java 内存模型 JMM 详解

    转载自 Java 内存模型 JMM 详解 JMM简介 Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性.是否可以重排序等问题的无关具体 ...

  2. Java内存模型(JMM)详解

    在Java JVM系列文章中有朋友问为什么要JVM,Java虚拟机不是已经帮我们处理好了么?同样,学习Java内存模型也有同样的问题,为什么要学习Java内存模型.它们的答案是一致的:能够让我们更好的 ...

  3. Java内存模型(JMM)详解!

    文章目录 什么是JMM? 现代计算机内存模型 缓存一致性 JMM内存模型与计算机内存模型的关系 线程间通信 JMM三大问题 原子性 可见性 有序性 volaile关键字详解! 什么是JMM? JMM定 ...

  4. JUC进阶之路-Java的内存模型JMM

    本文源自转载:JUC进阶之路-Java的内存模型JMM 目录 一.大厂常见的JMM面试题 二.什么是JAVA内存模型JMM(Java Memory Model) 三.JMM的三大特性 3.1 可见性 ...

  5. Java多线程之线程池详解

    Java多线程之线程池详解 目录: 线程池使用及优势 线程池3个常用方式 线程池7大参数深入介绍 线程池底层工作原理 1. 线程池使用及优势 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务 ...

  6. JMM(Java 内存模型)详解

    CPU 缓存模型 为什么要弄一个 CPU 高速缓存(CPU Cauche)呢? 类比我们开发网站后台系统使用的缓存(比如 Redis)是为了解决程序处理速度和访问常规关系型数据库速度不对等的问题. C ...

  7. java 取栈顶元素_《Java实战之内存模型》详解篇

    内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的实时运行 JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的高效稳定运行 不同的JV ...

  8. java 死锁 内存消耗_详解Java中synchronized关键字的死锁和内存占用问题

    先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并 ...

  9. java多线程内存模型_Java多线程内存模型

    Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果.在此之前 ...

  10. JAVA多线程Thread VS Runnable详解

    进程与线程 进程是程序在处理机中的一次运行.一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立.所以进程是重量级的任务,它们之间的通信和转换都需要操作系统 ...

最新文章

  1. 电脑壁纸励志_励志壁纸 | 要乖 要长大 要努力 要不负众望
  2. Machine Learning | (2) sklearn数据集与机器学习组成
  3. php5.3二进制包,php使用pack处理二进制文件的方法
  4. linux 网络7层模型,Linux网络编程——OSI七层模型、TCP/IP模型
  5. lol战绩查询接口_大聪明,3000元配置一台能畅玩LOL、CF、DNF的腾讯全家桶电脑,该怎么办?——12.10更新...
  6. Tiniux 3.0 / Memory.c / OSMemInit
  7. mybatis-plus设置查询返回的类型是map
  8. postfix本机测试本机时,telnet连接出错
  9. java算法概述,Java数据结构与算法基础(一)概述与线性结构
  10. mysql between 等于_MySQL中BETWEEN子句的用法详解
  11. 表级触发器不支持ddl语句_用于视图,过程和函数的数据库级DDL触发器
  12. 游戏外挂设计技术探讨(上)
  13. 静态常量static和方法重载
  14. Java泛型之类型擦除
  15. java技术架构选型方案报告.pdf,来啦,2020开源报告!
  16. 实验固体力学类毕业论文文献包含哪些?
  17. JavaScript常见的六种继承方式
  18. WiFi密码破解亦或是WiFi热点软件?
  19. 基于java的KTV点歌选歌系统
  20. vue使用video和vue-video-player并且可实现视频铺满呦

热门文章

  1. ajax接收反参时,接收到[object XMLDocument]时的处理方法
  2. 浅析游戏音效制作后期的创新
  3. TJUPT 无法与服务器建立连接问题的解决方法
  4. 好玩的ios APP动动手指,轻松挣美金~~
  5. 2022年起重机械指挥特种作业证考试题库及答案
  6. BZOJ3509. [CodeChef] COUNTARI
  7. 《隐私保护周三见》精彩50问 | 交流群互动合集
  8. java js 二级联动下拉列表_最简单js代码实现select二级联动下拉菜单
  9. 你还在用乞丐版的深拷贝么
  10. ArcGIS Pro功能模块简介