栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java有序性问题深入分析 & 内存屏障多层面深入理解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java有序性问题深入分析 & 内存屏障多层面深入理解

文章目录
  • 一、有序性问题深入分析
  • 二、指令重排序
    • 2.1 volatile重排序规则
    • 2.2 JMM内存屏障插入策略
    • 2.3 JSR133规范
  • 三、深入理解内存屏障
    • 3.1 JVM层面的内存屏障
    • 3.2 硬件层内存屏障

一、有序性问题深入分析

思考:下面的Java程序中x和y的最终结果是什么?

public class ReOrderTest {

    private static int x = 0, y = 0;

    private static  int a = 0, b = 0;

    public static void main(String[] args) throws InterruptedException{
        int i=0;
        while (true) {
            i++;
            x = 0;
            y = 0;
            a = 0;
            b = 0;

            
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    shortWait(20000);
                    a = 1;
                    x = b;

                }
            });
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    b = 1;
                    y = a;
                }
            });

            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();

            System.out.println("第" + i + "次(" + x + "," + y + ")");

            if (x == 0 && y == 0){
                break;
            }

        }

    }

    public static void shortWait(long interval){
        long start = System.nanoTime();
        long end;
        do{
            end = System.nanoTime();
        }while(start + interval >= end);
    }
二、指令重排序

ava语言规范规定JVM线程内部维持顺序化语义。即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的重排序。

指令重排序的意义: JVM能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重排序,使机器指令能更符合CPU的执行特性,最大限度的发挥机器性能。

在编译器与CPU处理器中都能执行指令重排优化操作。

2.1 volatile重排序规则


volatile禁止重排序场景:
1、第二个操作是volatile写,不管第一个操作是什么都不会重排序
2、第一个操作是volatile读,不管第二个操作是什么都不会重排序
3、第一个操作是volatile写,第二个操作是volatile读,也不会发生重排序

2.2 JMM内存屏障插入策略
  1. 在每个volatile写操作的前面插入一个StoreStore屏障
  2. 在每个volatile写操作的后面插入一个StoreLoad屏障
  3. 在每个volatile读操作的后面插入一个LoadLoad屏障
  4. 在每个volatile读操作的后面插入一个LoadStore屏障
2.3 JSR133规范

https://blog.csdn.net/qq_43631716/article/details/114760621

86处理器不会对读-读(LoadLoad)、读-写(LoadStore)和写-写(StoreStore)操作做重排序, 会省略掉这3种操作类型对应的内存屏障仅会对写-读(StoreLoad)操作做重排序,所以volatile写-读操作只需要在volatile写后插入StoreLoad屏障

三、深入理解内存屏障 3.1 JVM层面的内存屏障

在JSR规范中定义了4种内存屏障:

1、LoadLoad屏障:(指令Load1; LoadLoad; Load2),在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

2、LoadStore屏障:(指令Load1; LoadStore; Store2),在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

3、StoreStore屏障:(指令Store1; StoreStore; Store2),在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见

4、StoreLoad屏障:(指令Store1; StoreLoad; Load2),在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

由于x86只有store load可能会重排序,所以只有JSR的StoreLoad屏障对应它的mfence或lock前缀指令,其他屏障对应空操作。

3.2 硬件层内存屏障

硬件层提供了一系列的内存屏障 memory barrier / memory fence(Intel的提法)来提供一致性的能力。

拿X86平台来说,有几种主要的内存屏障:

1、lfence,是一种Load Barrier 读屏障

2、sfence, 是一种Store Barrier 写屏障

3、mfence, 是一种全能型的屏障,具备lfence和sfence的能力

4、Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。 它后面可以跟ADD, ADC,AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG等指令。

内存屏障有两个能力:
1、阻止屏障两边的指令重排序
2、刷新处理器缓存/冲刷处理器缓存


Load Barrier(Ifence)来说,在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据;

Store Barrier(sfence)来说,在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存。


Lock前缀实现了类似的能力,它先对总线和缓存加锁,然后执行后面的指令,最后释放锁后会把高速缓存中的数据刷新回主内存。在Lock锁住总线的时候,其他CPU的读写请求都会被阻塞,直到锁释放。


不同硬件实现内存屏障的方式不同,Java内存模型屏蔽了这种底层硬件平台的差异,由JVM来为不同的平台生成相应的机器码。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/390165.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号