类似物理上的计算机系统,Java虚拟机规范中也定义了一种Java内存模型,即Java Memory Model(JMM),
来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。
现在最新的Java内存模型规范是JSR-133,即Java内存模型与线程规范,这套规范包含:
线程之间如何通过内存通信;
线程之间通过什么方式通信才合法,才能得到期望的结果。

理解内存模型对Java的并发编程有很大的帮助。

>>Java内存模型

JMM决定一个线程对共享变量的写入何时对另一个线程可见。
定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。
本地内存是一个抽象概念,并不真实存在,涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

(1)主内存和本地内存
主内存即main memory。在java中,实例域、静态域和数组元素是线程之间共享的数据,它们存储在主内存中。
本地内存即local memory。 局部变量,方法定义参数 和 异常处理器参数是不会在线程之间共享的,它们存储在线程的本地内存中。
(2)原子性
是指一个操作是按原子的方式执行的。要么该操作不被执行;要么以原子方式执行,即执行过程中不会被其它线程中断。

>>重排序

重排序是指“编译器和处理器”为了提高性能,而在程序执行时会对程序进行的重排序。
重排序分为——“编译器”和“处理器”两个方面,而“处理器”重排序又包括“指令级重排序”和“内存的重排序”。
关于重排序,我们需要理解它的思想:为了提高程序的并发度,从而提高性能!但是对于多线程程序,重排序可能会导致程序执行的结果不是我们需要的结果!因此,就需要我们通过“volatile,synchronize,锁等方式”作出正确的实现同步。

>>内存屏障

内存屏障包括LoadLoad, LoadStore, StoreLoad, StoreStore共4种内存屏障。内存屏障是与相应的内存重排序相对应的。
通过内存屏障可以禁止特定类型处理器的重排序,从而让程序按我们预想的流程去执行。

>>顺序一致性

顺序一致性内存模型是理想化的内存模型。有以下规则:
(1)一个线程中的所有操作必须按照程序的顺序来执行。
(2)所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且立刻对所有线程可见。

>>锁

锁是java并发编程中最重要的同步机制。
(1)锁的内存语义:
线程A释放一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A对共享变量所做修改的)消息。
线程B获取一个锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息。
线程A释放锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发送消息。

(2)JMM如何实现锁
公平锁是通过“volatile”实现同步的。公平锁在释放锁的最后写volatile变量state;在获取锁时首先读这个volatile变量。根据volatile的happens-before规则,释放锁的线程在写volatile变量之前可见的共享变量,在获取锁的线程读取同一个volatile变量后将立即变的对获取锁的线程可见。

非公平锁通过CAS实现的,CAS就是compare and swap。CAS实际上调用的JNI函数,也就是CAS依赖于本地实现。以Intel来说,对于CAS的JNI实现函数,它保证:
禁止该CAS之前和之后的读和写指令重排序。
把写缓冲区中的所有数据刷新到内存中。

>>final域

对于基本类型的final域,编译器和处理器要遵守两个重排序规则:
(1)final写:“构造函数内对一个final域的写入”,与“随后把这个被构造对象的引用赋值给一个引用变量”,这两个操作之间不能重排序。
(2)final读:“初次读一个包含final域的对象的引用”,与“随后初次读对象的final域”,这两个操作之间不能重排序。
对于引用类型的final域,除上面两条之外,还有一条规则:
(3)final写:在“构造函数内对一个final引用的对象的成员域的写入”,与“随后在构造函数外把这个被构造对象的引用赋值给一个引用变量”,这两个操作之间不能重排序。
写final域的重排序规则可以确保在引用变量为任意线程可见之前,该引用变量指向的对象的final域已经在构造函数中被正确初始化过了。其实要得到这个效果,还需要一个保证:在构造函数内部,不能让这个被构造对象的引用为其他线程可见,也就是对象引用不能在构造函数中“逸出”。
JMM通过“内存屏障”实现final,在final域的写之后,构造函数return之前,插入一个StoreStore障屏。在读final域的操作前面插入一个LoadLoad屏障。

参考 InfoQ·深入理解Java内存模型

对Java内存模型即JMM的理解的更多相关文章

  1. Java内存模型(JMM)那些事

    本文是库存文章,去年年底学习了慕课网的并发编程课程,今年年初看完了<深入理解Java虚拟机>这本书,但是很多内容忘得差不多了,打算写写博客回忆一下那些忘在脑后的知识点. 温故而知新 更多J ...

  2. java多线程的基础-java内存模型(JMM)

    在并发编程中,需要处理两个关键问题:线程之间如何通信,以及线程之间如何同步.通信是指线程之间如何交换信息,在命令式编程中,线程之间的通信机制有两种:内存共享和消息传递.      同步是指程序中用于控 ...

  3. Java线程之Java内存模型(jmm)

    一.Java内存模型(jmm) 线程通信 消息传递 重排序 顺序一致性 Happens-Before As-If-Serial

  4. Java 并发系列之三:java 内存模型(JMM)

    1. 并发编程的挑战 2. 并发编程需要解决的两大问题 3. 线程通信机制 4. 内存模型 5. volatile 6. synchronized 7. CAS 8. 锁的内存语义 9. DCL 双重 ...

  5. Java内存模型解惑--观深入理解Java内存模型系列文章有感(二)

    1.volatile关键字修饰的域的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用 ...

  6. Java内存模型(JMM)以及 垃圾回收机制 小结

    内存模型: 内存模型描述了程序中各个变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节,对象最终是存储在内存里面的,这点没有错,但是编译 ...

  7. java内存模型(jMM)(一)

    在说java的内存模型之前先简单的了解计算机的主存和缓存的相关概念. 多任务和高并发是衡量一台计算机处理器的重要指标.一般衡量一个服务器性能的高低好坏,使用每秒事务处理数(Transactions P ...

  8. Java并发-Java内存模型(JMM)

    先来说说什么是内存模型吧 在硬件中,由于CPU的速度高于内存,所以对于数据读写来说会出现瓶颈,无法充分利用CPU的速度,因此在二者之间加入了一个缓冲设备,高速缓冲寄存器,通过它来实现内存与CPU的数据 ...

  9. Java内存模型(JMM)

    JVM与线程(线程在JVM中) 1.JVM什么时候启动?         类被调用时启动,此时会启动JVM线程然后再是其他的线程(main) 2.JVM内存区域 除了程序计数器(PC)之外都有可能发生 ...

随机推荐

  1. Sqli-LABS通关笔录-12

    通过这个关卡我学习到了: 1.双引号千万别忘记,就是因为忘了弄了好一会儿.一直不报错. 2. 00x1万能密码构造二 报错的内容为: You have an error in your SQL syn ...

  2. 一起入门python7之函数参数

    上一节课简单的讲了一下函数.那么今天来给大家讲一下函数参数.用案例说话哈.上一节课只是让大家有比较简单的了解,那么这节我们来细化一下哈.>>>def hello(x):        ...

  3. BZOJ 1044: [HAOI2008]木棍分割

    Description 求 \(n\) 根木棍长度为 \(L\) ,分成 \(m\) 份,使最长长度最短,并求出方案数. Sol 二分+DP. 二分很简单啊,然后就是方案数的求法. 状态就是 \(f[ ...

  4. 正在使用广告标识符 (IDFA)

    APP提交审核后,apple方面一直说我使用了IDFA,APP里没有集合任何广告SDK. 怀疑是其他第三方的SDK用了. 检测命令 //在项目的根目录下用终端执行 grep -r advertisin ...

  5. 常用浏览器user_agent大全

    PC端: safari 5.1 – MACUser-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit ...

  6. github 多个项目共用同一个key的方法

    后面的项目不用添加ssh keys, 直接在项目下设置合作者(Collaborators), 搜索出去加进去即可免密码传代码.

  7. centos 安装gcc时,出错:Found 10 pre-existing rpmdb problem(s), 'yum check' output follows:

    别人折腾的系统. 刚开始,准备安装下tornado,报错,需要安装 gcc 和 python-devel gcc安装报错,如标题所示: 谷歌了一把: http://stackoverflow.com/ ...

  8. ios NSString 转 float的注意

    今天有一个字符串 “33.3”,用想用[valueString floatValue];得到33.3000这个值,结果得到了33.2999这个值,取前3位一个是33.3,一个是33.2,产生了错误,应 ...

  9. codevs 3290 华容道(SPFA+bfs)

    codevs 3290华容道 3290 华容道 2013年NOIP全国联赛提高组 时间限制: 1 s  空间限制: 128000 KB 题目描述 Description 小 B 最近迷上了华容道,可是 ...

  10. 【linux】jdk安装

    1.在http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载最新版的rpm文件,我 ...