JMM-Java内存模型

JMM由来


Java语言规范规定了JVM要维护内部线程类似顺序化语言:
只要程序的最终结果等同于它在严格顺序化环境中执行的结果,允许编译器生成指令的次序跟源代码的次序不同,并且处理器可以乱序或者并行地执行指令,可以改变将处理器的高速缓存(寄存器)写入提交到主内存的变量的次序,所以存储在处理器缓存中的值,对于其他处理器并不可见。
那为什么编译器改变源代码的执行次序,在近些年重新排序后的指令使得程序在计算性能上得到了很大的提升,重新排序后的指令,对于优化执行以及成熟的全局寄存器分配算法的使用,是有很大用处的。

当有多个线程要共享数据时,必须协调它们的活动;协调是通过使用同步来完成的,JVM依赖于程序明确地指出何时需要协调线程的活动。
JMM规定了JVM的一种最小保证:什么时候写入一个变量会对其他线程可见的。

JMM介绍


JMM的定义是通过动作的形式进行描述的,这些动作,包括变量的读和写、监视器加锁和释放锁、线程的start和join。

JMM为所有程序内部的动作定义了一个偏序关系,叫happens-before。想要执行动作B的线程看到动作A的结果(无论A和B是否发生在同一个线程中),A和B之间就必须满足happens-before关系。如果两个操作之间并未依照happens-before关系,则JVM可以对它们随意地重排序。

重排序

包括:
编译器生成指令的次序,可以不同于源代码所暗示的“显然”版本。
处理器可以乱序或者并行的执行指令。
缓存会改变写入提交到主内存的变量的次序。


当一个变量被多个线程读取,而且还会至少一个线程写入时,如果这个变量的读写操作不满足happens-before排序关系时,则这个变量就会产生数据竞争(data race)。正确同步的程序(correctly synchronized program)是没有数据竞争的程序;正确同步的程序会表现出顺序的一致性, 这就是说所有程序内部的动作会以固定的、全局的顺序发生。

happens-before的法则


程序次序法则:线程中的每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有的动作B都出现在动作A之后。
监视器锁法则:对一个监视器锁的解锁happens-before于每一个后续对同一个监视器锁的加锁。
volatile变量法则:对volatile变量的写入操作happens-before于每一个后续对同一变量的读操作。
线程启动法则:线程中的任何动作都happens-before于其他线程检测到这个线程已经终结、或者从Thread.join调用中成功返回,或者Thread.isAlive返回false。
中断法则:一个对象的构造函数的结束happens-before于这个对象finalizer的开始。

传递性:如果A happens-before于 B,且B happens-before于 C,则A happens-before于 C。

对同步排序的进一步发挥


结合“程序次序法则”和另一种法则(一般是“监视器法则”或者“volatile变量法则”)来对访问变量的操作进行排序,或者用锁来控制对变量的访问,这是用来提高性能的一种高级使用,如,或重入锁class ReentrantLock。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值