Java的内存模型

Java内存模型(JMM)是一个抽象的模型。决定了线程主要定义了线程和内存间的抽象关系:主内存存放的是线程共享变量,每个线程有自己的工作内存,存放变量的副本,只能对副本进行读写,副本的变量再刷新到主内存中。具体体现为多核CPU,每核有一个高速缓存,每个核的线程对高速缓存读写,并且有共同的主存。

主内存与工作线程交互的操作有以下八种:

lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态

unlock(解锁):作用于主内存的变量,释放锁定状态的变量

read(读取):作用于主内存的变量,把一个变量从主内存传输到线程的工作内存中,以便随后的load动作使用

load(载入):作用于工作内存的变量,把read操作从主内存中得到的变量值放入工作内存的变量副本中。

use(使用):作用于工作内存的变量,把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作

assign(赋值):作用于工作内存的变量,把一个从执行引擎收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时将会执行这个操作

store(存储):作用于工作内存的变量,把工作内存的一个变量值传送到主内存,以便随后的write操作使用

write(写入):作用于主内存的变量,把store操作从工作内存得到的变量的值放入主内存变量中

上述八种操作均是原子操作。

如上图,若A和B两个线程同时去主存读写变量C,就会存在线程安全问题(可见性和有序性)。

Happens-Before原则

在JMM中,两个线程操作之间存在happens-before关系,则前一个操作的结果对后续操作可见。即使编译器进行指令重排序的优化,如果结果和重排序前一致,也是允许的。

因为允许指令重排序,这也说明 happens-before并不代表操作的时间顺序。

有如下8条规则:

1.程序次序规则:单线程内,按照程序顺序,书写在前面的操作 happens-before 于书写在后面的操作;

2.volatile变量规则:对一个变量的写操作happens-before于后面对这个变量的读操作(保证了volatile变量的可见型);

3.传递规则:如果 A happens-beforeB,而B happens-beforeC,则A happens-beforeC;

4.锁定规则:一个unLock操作happens-before后面对同一个锁的lock操作;

5.线程启动规则:A线程调用B线程的B.start()方法和调用之前的操作 happens-before于B线程中的任意操作;

6.线程终结规则:线程中所有的操作都 happens-before于线程的终止检测,如B线程的操作都happens-before 于B.join();

7.线程中断规则:对线程interrupt()方法的调用 happens-before于被中断线程的代码检测到中断事件的发生;

8.对象终结规则:一个对象的初始化完成 happens-before他的finalize()方法的开始

Volatile关键词

java1.5之后,通过happen-before原则增强了volatile关键词。volatile关键词是轻量的实现线程安全的方法,保证了volatile变量的有序性和可见性。

1.volatile保证了变量在线程间的可见性(MESI 协议):

当写 volatile 变量时,JMM 会立即该线程对应的本地内存中的共享变量值刷新到主内存。

当读 volatile 变量时,JMM 会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

volatile 保证内存可见性,其实是用到了CPU 保证缓存一致性的 MESI 协议。当某线程对 volatile 变量的修改会立即回写到主存中,并且导致其他线程的缓存行失效,强制其他线程再使用变量时,需要从主存中读取。

2.volatile保证了有序性(内存屏障):

volatile变量在读写操作前后添加内存屏障,禁止了指令的重排序,保证了有序性。

内存屏障有LoadLoad屏障,StoreStore屏障,LoadStore屏障,StoreLoad屏障。比如loadload屏障,加在Load1; Load2两个原子操作之间 ,保证在Load2及后续的读操作读取之前,Load1已经读取。其他同理。

在每个volatile写入之前,插入一个StoreStore,写入之后,插入一个StoreLoad

在每个volatile读取之前,插入LoadLoad,之后插入LoadStore。

禁止重排序规则如下图。

3.volatile无法保证原子性,只能保证自身读写为原子操作。

对volatile变量的读写 相当与给读写方法加了synchronized关键词,但volatile更轻量级。

例子

最经典的例子就是单例模式的双重检查锁模式

这里instance变量需要设置为volatile类型,这样可以保证它的new操作不会被重排序。

因为这段代码可能在重排序后分为下列三步执行:

为 instance分配内存空间

将 instance指向分配的内存地址

初始化 instance

这样在执行2时,别的线程就会判断instance不为null,直接返回还未实例化完全的instance。

并且可以知道volatile修饰的instance变量的new操作并不是原子操作,否则也就不需要synchronized加锁来保证原子性了。

总结:

JMM内存模型定义了线程和内存间的抽象关系,实际的例子就是cpu核线程,高速缓存和主存间的关系;

happens-before原则的规定保证了操作间的可见性。

volatile变量保证了有序性和可见性。主要是内存屏障和MESI 协议实现的。volatile变量的读写操作为原子操作,本身其他操作(如自增)是非原子操作。

java很贵可以用before代替吗_Java内存模型与Volatile,Happen-Before原则等相关推荐

  1. JMM Java内存模型的概念以及happens-before原则

    详细介绍了JMM Java内存模型的概念.由来,以及happens-before原则的具体规则. Java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的一组规范以及机 ...

  2. java内存规范_Java内存模型-jsr133规范介绍

    最近在看<深入理解Java虚拟机:JVM高级特性与最佳实践>讲到了线程相关的细节知识,里面讲述了关于java内存模型,也就是jsr 133定义的规范. 系统的看了jsr 133规范的前面几 ...

  3. java内存模型 原子性_Java内存模型JMM 高并发原子性可见性有序性简介 多线程中篇(十)...

    JVM运行时内存结构回顾 在JVM相关的介绍中,有说到JAVA运行时的内存结构,简单回顾下 整体结构如下图所示,大致分为五大块 而对于方法区中的数据,是属于所有线程共享的数据结构 而对于虚拟机栈中数据 ...

  4. 内存位置访问无效_万字长文——java内存模型之volatile深入解读

    在阅读本文前,请思考以下的面试题? volatile是什么? volatile的特性 volatile是如何保证可见性的? volatile是如何保证有序性的? volatile可以保证原子性吗? 使 ...

  5. Java内存模型、volatile、原子性、可见性、有序性、happens-before原则

    目录 1.硬件的效率与一致性: 缓存一致性(Cache Coherence) 2.Java内存模型 2.1主内存与工作内存 2.2内存间的交互 2.3 volatile型变量的特殊规则 2.3.1 保 ...

  6. java并发-内存模型与volatile

    JMM的关键技术点都是围绕着多线程的原子性.可见性和有序性来建立的.因此,我们首先必须了解这些概念 1,原子性 原子性是指一个操作是不可中断的.即使是在多个线程一起执行的时候,一个操作一旦开始,就不会 ...

  7. java和硬件交互_Java内存模型

    Java内存模型 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存模式是一种虚拟机规范,真实并不存在 Java虚拟机规范中定义了Java内存模型(Java Memory Model,JM ...

  8. Java千百问_07JVM架构(001)_java内存模型是什么样的

    1.什么是内存模型 Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉害很多.Java针对多种异构平台的独立性,使得多线程技术也具有了开拓性的一面.  我们有时 ...

  9. java 线程内存模型_JAVA内存模型与线程

    概述 由于计算机的运算速度和它的存储和通讯子系统的速度差距巨大,大部分时间都花在IO,网络和数据库上.为了压榨CPU的运算能力,需要并发.另外,优秀的并发程序对于提高服务器的TPS有重要的意义. 硬件 ...

最新文章

  1. oracle 错误2 启动服务提示找不到指定文件_Weblogic中间件创建文件权限问题解决...
  2. Codeforces Round #504 E - Down or Right 交互题
  3. 快讯 | 美国投资公司Avenue Capital Group联合创始人Marc Lasry:比特币价格可能达到40,000美元...
  4. Py之utils:utils库的简介、安装、使用方法之详细攻略
  5. 什么是反射和字节码对象。
  6. ABAP 后台作业的一个状态查询工具
  7. 如果信用卡欠款不还被坐牢,那所欠的钱还用还吗?
  8. 05.序列模型 W1.循环序列模型(作业:手写RNN+恐龙名字生成)
  9. 阿里云 超级码力在线编程大赛初赛 第2场 题目3. 五字回文
  10. SaaS模式云数据仓库:持续保护云上数据及服务安全
  11. Visio——软件工程实验贰——面向对象软件设计方法
  12. 想做DBA,多租户管理你一定要知道这些
  13. ubuntu命令整理中
  14. 6.4 tensorflow2实现FNN推荐系统——Python实战(第二篇)
  15. 图形 安装ubuntu_Ubuntu怎么下载应用并安装应用
  16. Atitit mysql存储过程编写指南 1. 定义变量 1 1.1. 变量名以@开头用户变量 会话变量 1 1.2. 以declare关键字声明 存储过程变量 2 1.3. @是用户自定义变量,
  17. ios定制中间突出的tabBar
  18. win7开机动画_win7电脑修改开机动画的操作方法
  19. 利用excel内的doi和python批量下载外文文献
  20. Chrome浏览器离线安装Axure插件

热门文章

  1. Titon Toolkit – 非常强大的用户界面组件
  2. Cisco ACS AAA服务器导入华为私有属性
  3. 一个worker thread服务一个客户端
  4. 100万并发连接服务器笔记之准备篇
  5. mysql 常用命令操作
  6. Oracle序列号详解
  7. Java高手需要注意的25个学习目标
  8. 201671010433 | 词频统计软件项目报告
  9. 定时器时间动态变化(变速)
  10. [django]Django输出页面方式的补充