Java内存模型

Java内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。

处理器上的寄存器读写速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。同时产生了缓存一致性问题,如果多个缓存共享同一块主内存区域,多个缓存的数据可能不一致,需要协议来解决这个问题。

所有的变量存储在主内存中,每个线程有自己的工作内存,工作内存存储在高速缓存或寄存器中,保存了该线程使用的变量的主内存副本拷贝。线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。

内存间交互

Java内存模型定义了8个操作来完成主内存和工作内存的交互操作。

  • read:把一个变量的值从主内存传输到工作内存中
  • load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
  • use:把工作内存中一个变量的值传递给执行引擎
  • assign:把一个从执行引擎接收到的值赋给工作内存的变量
  • store:把工作内存的一个变量的值传送到主内存中
  • write:在 store 之后执行,把 store 得到的值放入主内存的变量中
  • lock:作用于主内存的变量
  • unlock

内存模型的三大特性

1. 原子性

原子性就是指一个操作中要么全部执行成功,否则失败。Java内存模型保证了上述的八个操作具有原子性。但是Java内存模型允许虚拟机将没有被volatile修饰的64位数据(long,double)的读写操作划分为两次32位操作进行,因此load,store,read和write操作不具备原子性。但是JMM只保证了上述操作的原子性,像是i++这样的操作,其实是分为获取i,i自增以及赋值给i三步的,如果要实现这样的原子操作就需要使用原子类实现,或者也可以使用它synchronized互斥锁来保证操作的原子性。

2. 可见性

可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。

可见性的三种是实现方式:

  • volatile
  • synchronized,对一个变量执行unlock操作之前,必须把变量值同步回主内存。
  • final,被 final关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。

使用 volatile 关键词修饰的变量每次读取都会得到最新的数据,不管哪个线程对这个变量的修改都会立即刷新到主内存。但是 volatile 关键字不能保证操作的原子性。

synchronized和加锁也能能保证可见性,实现原理就是在释放锁之前其余线程是访问不到这个共享变量的。但是和 volatile 相比开销较大。

3. 顺序性

假设有三个语句a,b,c。在同一个线程内,操作是有序的,以a->b->c的顺序执行。但是,JMM在保证最终结果和代码顺序执行结果一致的情况下,为了提高整体效率会进行指令重排。在单线程中重排不会问题,在多小县城中,可能会有数据不一致的问题。

Java中可以使用volatile关键字来保证顺序性,还可以用synchronized和lock来保证。

volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。

通过 synchronized 和 lock 来保证有序性,它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码。

JVM通过happen-before来保证顺序性

除了使用volatile和synchronized保证顺序性,JVM还规定了先行发生原则,让一个操作无需控制就能先于另一个操作完成。

  1. 单一线程原则:在一个线程内,程序前面的操作先于后面的操作。
  2. 管程锁定规则:一个unlock操作先于后面对同一个锁的lock操作发生。
  3. volatile变量规则:对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作,也就是说读取的值肯定是最新的。
  4. 线程启动规则:Thread对象的start()方法调用先行发生于此线程的每一个动作。
  5. 线程加入规则:Thread 对象的结束先行发生于 join() 方法返回。
  6. 线程中断规则:对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。
  7. 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize() 方法的开始。
  8. 传递性:如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。

参考资料

  • github.com/CyC2018/CS-…
  • crossoverjie.top/JCSprout/#/…

Java多线程编程笔记4:Java内存模型相关推荐

  1. java多线程编程_《java多线程编程实战指南》读书笔记 -- 基本概念

    展开 并发:多个线程操作相同资源,保证线程安全,合理使用资源 高并发:服务能同时处理多个请求,提高程序性能 测试上下文切换工具 Lmbench3 测量上下文切换时长 vmstat 测量上下文切换次数 ...

  2. 深入理解Java虚拟机学习笔记-1.JVM内存模型

    JVM内存模型 1.内存模型结构图 名称 特征 作用 配置参数 异常 程序计数器 占用内存小,线程私有, 生命周期与线程相同 大致为字节码行号指示器 无 无 虚拟机栈 线程私有,生命周期与线程相同,使 ...

  3. java 静态代码块 多线程,Java多线程编程笔记10:单例模式

    立即加载:"饿汉模式" 立即加载就是指使用类的时候已经将对象创建完毕,常见的实现方法就是直接new实例化.也就是在调用方法前,实例就被创建了.示例代码如下所示: class MyO ...

  4. Java多线程编程笔记之Condition

    本篇内容基于JDK7,涉及Condition常用方法. 1.概述 Condition接口位于java.util.concurrent.locks包下,实现类有 AbstractQueuedLongSy ...

  5. Java并发编程笔记之ThreadLocal内存泄漏探究

    使用 ThreadLocal 不当可能会导致内存泄露,是什么原因导致的内存泄漏呢? 我们首先看一个例子,代码如下: /*** Created by cong on 2018/7/14.*/ publi ...

  6. 《Java多线程编程核心技术》读书笔记

    为什么80%的码农都做不了架构师?>>>    <Java多线程编程核心技术>读书笔记. ###第一章 Java多线程技能 使用Java多线程两种方式. 继承Thread ...

  7. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  8. Java多线程编程那些事:volatile解惑--转

    http://www.infoq.com/cn/articles/java-multi-thread-volatile/ 1. 前言 volatile关键字可能是Java开发人员"熟悉而又陌 ...

  9. Java多线程编程模式实战指南(二):Immutable Object模式--转载

    本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-o ...

最新文章

  1. Windows下开源缺陷跟踪系统mantis安装指南(续)-
  2. html弹窗确认取消公告代码,js 弹出确认与取消对话框的四种方法
  3. 添加用户信息的方法java_添加用户的流程分析
  4. 飞书上点链接怎么指定跳转浏览器_链接示例表功能还可以这样用??
  5. 【spring boot】支持webjars
  6. Redis集群一致性Hash效果的代码演示
  7. Ubuntu 安装R/Rstudio
  8. NOIP 2013 day2
  9. 邮件里直接显示图片_利用邮件合并带图片功能批量制作准考证、工作证、成绩通知单等...
  10. vue2.x使用jsoneditor编辑器
  11. 体脂率在线计算机,如何简单测算出自己的体脂率?
  12. pageSize不生效
  13. ubuntu--制作图标
  14. WPF入门教程(一)---基础
  15. 如何设计好的RESTful API?
  16. 单元格等于计算机日期,Excel相邻单元格快速填入相同日期的几种方法
  17. python爬虫,虎牙房间爬取(selenium)
  18. 次世代游戏建模师一个月的工资有多少?
  19. 用AI给黑白照片上色,复现记忆中的旧时光
  20. Android7.1 Kyguard界面灭屏时间分析

热门文章

  1. express 随笔
  2. CentOS安装fortune+cowsay
  3. ionic + cordova 使用 cordova-gallery-api 获取本地相册所有图片
  4. javascript获取asp.net后台代码的方法
  5. Tech.Ed 2008
  6. HTML在手机上实现直接拨打电话以及发送短信
  7. c语言小项目---通讯录2.0
  8. .NET Core整合log4net以及全局异常捕获实现2
  9. 5904.刺客信条(AC)
  10. 动态规划--背包问题