Java四种内存屏障详解,LoadLoad、LoadStore、StoreLoad、StoreStore

由于没在官网查到相关资料,以下结论来自互联网第三方博客搜集整理后,准确性无法保证,仅供参考。

 

屏障作用:

  1. 可见性:当一条线程修改了一个变量的值,新值会立即被写入主内存,同时其他线程读取该变量时会从主内存中读取最新值,而不是使用线程缓存中的值。

  2. 有序性:编译器和处理器可能会对指令进行重排以提高性能,但这种重排可能会导致其他线程看到不一致的状态。变量的读写操作前后会插入特定的内存屏障,这些屏障会禁止指令重排,从而保证了操作的顺序性。

 

屏障类别:

  1. LoadLoad(读读屏障):先执行屏障前的 ,后执行屏障后的
  2. LoadStore(读写屏障):先执行屏障前的 ,后执行屏障后的
  3. StoreLoad(写读屏障):先执行屏障前的 ,后执行屏障后的
  4. StoreStore(写写屏障):先执行屏障前的 ,后执行屏障后的

 

插入时机表:

屏障需求 第二个操作
第一个操作 普通读 普通写

volatile读

获取锁

volatile写

释放锁

普通读       LoadStore
普通写       StoreStore

volatile读

获取锁

LoadLoad LoadStore LoadLoad LoadStore

volatile写

释放锁

    StoreLoad StoreStore

 

代码示例:

class X {
    int a, b;
    volatile int v, u;

    void f() {
        int i, j;

        i = a;     // load a
        j = b;     // load b
        
        /* 为什么这里volatile读之前不插入屏障?如何保证可见性?
         * 因为其他线程的volatile写后的屏障必然会让新值同步过来
         * 所以这里无需屏障
         */
        i = v;     // load v
                   //    LoadLoad    - volatile读 和 volatile读 之间插入LoadLoad
        j = u;     // load u
                   //    LoadStore   - volatile读 和 普通写 之间插入LoadStore
        a = i;     // store a
        b = j;     // store b
                   //    StoreStore  - 普通写 和 volatile写 之间插入StoreStore
        v = i;     // store v
                   //    StoreStore  - volatile写 和 volatile写 之间插入StoreStore
        u = j;     // store u
                   //    StoreLoad   - volatile写 和 volatile读 之间插入StoreLoad
        i = u;     // load u
                   //    LoadLoad    - volatile读 和 普通读 之间插入LoadLoad
                   //    LoadStore   - volatile读 和 普通写 之间插入LoadStore
        j = b;     // load b
        a = i;     // store a
    }
}
posted @ 2024-04-10 01:13  Yfeil  阅读(437)  评论(0编辑  收藏  举报