摘要:JMM学习笔记
正文:
Java Memory Model
未同步的程序的行为
如上面例子所示
有 A B 两个共享变量,r1 r2 两个局部变量
要出现 **May observer r2 == 2,r1 == 1 ** 线程执行顺序应该是如下所示:
Thread 1:B=1
Thread 2:r1=B
Thread 2:A=2
Thread 1:r2=A
而按照程序员视角看第一个原始指令与实际的结果,可能会感觉很困惑,其根本原因是Java 的语义允许编译器和微处理器进行优化,这则会影响未正确同步的代码的行为 (如上代码是未同步的)。
非正式语义
看一个程序是否被正确的同步有两个关键概念
冲突访问
对共享元素存在数据竞争场景,如上文中的未同步程序的行为
Happens-Before 关系
happens-before
关系可以对两个动作进行排序,如果一个动作 happens-before
另一个动作,则第一个对第二个可见,且第一个排在第二个之前。必须强调的是,两个动作之间存在 happens-before
关系并不意味着这些动作在Java中必须以这种顺序发生。happens-before
关系主要用于强调两个有冲突的动作之间的顺序,以及定义数据争用的发生时机
如果某个动作A
happens-before
动作B,且Bhappens-before
动作C,则有Ahappens-before
C
顺序一致性
顺序一致性是程序执行过程中可见性和顺序的强有力保证,在顺序一致性内存模型中,每个操作都必须是原子执行且对所有线程可见
final 字段
声明为 final 的字段在 对象完全初始化后的时刻 值是不可变的,所以 final 字段也允许编程人员在不需要同步的情况下实现线程安全的不可变对象
什么是内存模型
内存模型可以看做为一组规则,规定了一个线程的写操作何时会对另一个线程可见
定义
Shared variables/Heap memory
能够在线程间共享的内存称为共享内存或堆内存,所有的实例字段,静态字段以及数组元素都存储在堆内存中,方法中的局部变量永远不会在线程间共享且不会被内存模型影响
Inter-thread Actions
线程间的动作是某一个线程执行的动作能被另一个线程探测或影响,比如lock某个管城、读写volatile变量
我们无需关心 Intra-thread 动作(线程内部) ,每个单线程需要遵守正确的 Intra-thread semantics
Intra-thread semantics
线程内语义是单线程程序的标准语义,线程内语义决定着某个线程孤立的执行过程,当从堆中读取值时,值是由内存模型决定的
Synchronization Actions
同步动作包括锁、解锁、读写 volatile 变量等动作