多线程一致性的硬件层支持
cpu计算数据流程
硬盘 -> 内存(缓存) -> cpu(缓存)
cpu内的缓存可能导致数据不一致问题
解决方案:
1、bus(总线锁) 老的cpu用,就是在CPU和内存交互都通过bus,bus中有锁
2、MESI(intel CPU)用的MESI协议:MESI协议是对数据标记的几种状态
还有很多协议,不同的CPU用不同的协议
现在CPU的数据一致性实现 = 缓存锁(MESI) + 总线锁(有些数据太大没有缓存)
伪共享
由于CPU内缓存是以**缓存行(64个字节)**为单位的,可能缓存行其他数据用不到,但是也在缓存行里,频繁的刷新缓存行
伪共享的解决
通过使用缓存行的对齐提高效率,
例如:把一个long 变量 前后都放七个long类型,long占8个字节,所以不管在哪,这个变量都自占一个缓存行,但是浪费内存,自己衡量。
乱序问题
乱序行程的原因:
几个有序执行让CPU执行,当CPU执行第一个时,可能去内存查这个数据。CPU的速度是内存的上百倍,如果等到内存返回结果再去执行,那么CPU效率也会降低,所以CPU进行了优化,后续的执行命令如果不依靠第一个命令,换句话说,没有执行顺序的必然联系,那么cpu不等第一个执行完,就回去执行接下来的命令。所以导致乱序
CPU有合并写机制,占有四个字节,比每次写6个字节要快
如果保障有序性
volatile有序
硬件保证有序性
- intel CPU级别的内存屏障,读屏障(lfence )、写屏障(sfence)、读写屏障(mfence)
- Lock 指令也可以
JVM级别如果规范
jvm只是规范,具体的实现依靠硬件
LoadLoad屏障: 对于这样的语句Load1; LoadLoad; Load2,
在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:
对于这样的语句Store1; StoreStore; Store2,
在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:
对于这样的语句Load1; LoadStore; Store2,
在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障: 对于这样的语句Store1; StoreLoad; Load2,
在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。
volatile的实现
1、字节码层面:在字节码层面就加了一个 ACC_VOLATILE的标识
2、JVM层面:在volatile内存区的读写 都加屏障
3、OS(操作系统)和硬件层面:不同的硬件不同的实现方式,Windows 用lock指令实现的
synchronize的实现
1、字节码层面:在字节码层面 monitorenter monitorexit
2、JVM层面:C C++调用了操作系统提供的同步机制
3、OS(操作系统)和硬件层面:X86,用lock指令实现的