一、如何保障不乱序,也就是保障有序性
1、硬件内存屏障
留神:这是 inter X86
1.1 sfence
store fence 在 sfence 指令后面的写操作必须在 sfence 指令后边的写操作前实现
如图:如果没有 sfence , 是不能保障操作 1 在操作 2 执行前就执行完的,有了 sfence 能力保障操作 1 和操作 2 的程序
1.2 lfence
load fence 指令前的读操作必须在 lfence 指令后边的读操作执行前执行
如图:如果没有 lfence 不能保障读操作 1 和 读操作 2 的程序,有了 lfence 就能够保障了
1.3 mfence
mix fence 是汇合了 sfence 和 lfence 的所有作用于一身,mfence 前边的读写操作必须在 mfence 后边读写操作开始之前实现
如图:mfence 能够保障 在执行读操作 2 和写操作 2 之前 必须执行完读操作 1 和写操作 1
1.4 其余
除了 fence 外,还有一些原子指令,比方 lock xxx
这些原子指令是一个 Full Barrier, 执行时会锁住内存子系统来保障执行程序
甚至跨多个 cpu
2.、JVM 级别标准
留神:jvm 这只是 jvm 的标准,具体实现要看虚拟机怎么实现
2.1 LoadLoad 屏障
保障读操作的程序,LoadLoad 前边的读操作必须在 LoadLoad 后边的读操作前实现
如图:LoadLoad 能保障 读操作 2 和者读操作 3 执行前 必须执行完读操作 0 和读操作 1
2.2 StoreStore 屏障
比照 LoadLoad 保障写操作有序
2.3 LoadStroe 屏障
比照 LoadLoad 保障读操作和写操作有序
2.4 StoreLoad 屏障
比照 LoadLoad 保障写操作和读操作有序
3、volatile 实现细节
3.1 字节码层面
这里用到 jclasslib 前边文章讲过怎么装置
public class VolatileTest {
int i;
volatile int x;
public static void main(String[] args) {}}
jclasslib 能够看进去:
i 的修饰符是 0x0000[]
x 的修饰符是 0x0040[volatile]
很显著,字节码层面就只是给加了 volatile 的属性加了一个标识
3.2 JVM 层面
在写操作 和 读操作前后加了屏障
前后加了屏障,保障了程序性
volatile 类型变量批改之后会立刻写回内存,也就是从工作内存写回到主内存(JMM 常识)
3.3 操作系统硬件层面
须要应用 hsdis 进行反汇编,也就是把 class 编译成汇编指令。深刻了解 Java 虚拟机(第三版),448 页有个例子,这里就不叙述了,其实作为理解即可,底层也是通过 sfence lfence mfence 或者 lock 实现的。
windows x86 是用过 lock 实现的
这里须要应用 hsdis,没有太大必要去应用,如果有趣味能够用一下,不是很难,当前有工夫写一篇简略利用的文章。
4、synchronize 实现细节
4.1 字节码层面
public class TestSync {synchronized void m(){ }
void n(){synchronized (this){}}
}
同样应用 jclasslib 看
能够看进去 办法是用了一个标识符,代码块应用了 monitorenter monitorexit 语句
4.2JVM 层面
c、c++ 调用操作系统提供的同步机制
4.3 操作系统硬件层面
x86: 应用的 lock cmpxchg 等 指令
只是作为理解,其实工作中很少能用到,感兴趣的能够依据具体的关键字进行查问
依照字节码、jvm、操作系统硬件层面 这三个层面了解即可
最初写一个面试题大家看看能答复上来吗?
- 形容一个一个对象的创立过程
- 对象在内存中的存储布局
- 对象头具体蕴含什么
- 对象是怎么定位的
- 对象怎么调配的
- Object o = new Object() 在内存中占用了多少字节
下一篇以这个题为例 写一篇文章
有问题欢送留言,也可公众号 留言(响应快):