Java关键字之volatile

2021-07-12  本文已影响0人  小丸子的呆地

内容大部分摘自马士兵教育

volatile用来修饰变量,保证其内存可见性,并且防止jvm或者cpu对其进行指令重排序。

volatile的用途

1.线程可见性

package com.mashibing.testvolatile;

public class T01_ThreadVisibility {
    private static volatile boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()-> {
            while (flag) {
                //do sth
            }
            System.out.println("end");
        }, "server").start();


        Thread.sleep(1000);

        flag = false;
    }
}

2.防止指令重排序

问题:DCL单例需不需要加volatile?

需要。

CPU的基础知识
package com.mashibing.juc.c_028_FalseSharing;
 
 public class T02_CacheLinePadding {
     private static class Padding {
         public volatile long p1, p2, p3, p4, p5, p6, p7; //
     }
 
     private static class T extends Padding {
         public volatile long x = 0L;
     }
 
     public static T[] arr = new T[2];
 
     static {
         arr[0] = new T();
         arr[1] = new T();
     }
 
     public static void main(String[] args) throws Exception {
         Thread t1 = new Thread(()->{
             for (long i = 0; i < 1000_0000L; i++) {
                 arr[0].x = i;
             }
         });
 
         Thread t2 = new Thread(()->{
             for (long i = 0; i < 1000_0000L; i++) {
                 arr[1].x = i;
             }
         });
 
         final long start = System.nanoTime();
         t1.start();
         t2.start();
         t1.join();
         t2.join();
         System.out.println((System.nanoTime() - start)/100_0000);
     }
 }
 

MESI

系统底层如何实现数据一致性

  1. MESI如果能解决,就使用MESI
  2. 如果不能,就锁总线

系统底层如何保证有序性

  1. 内存屏障sfence mfence lfence等系统原语
  2. 锁总线

volatile如何解决指令重排序

1: volatile i

2: ACC_VOLATILE

3: JVM的内存屏障

屏障两边的指令不可以重排!保障有序!

happends-before 

as - if - serial

4:hotspot实现

bytecodeinterpreter.cpp

int field_offset = cache->f2_as_index();
          if (cache->is_volatile()) {
            if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
              OrderAccess::fence();
            }

orderaccess_linux_x86.inline.hpp

inline void OrderAccess::fence() {
  if (os::is_MP()) {
    // always use locked addl since mfence is sometimes expensive
#ifdef AMD64
    __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
#else
    __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
#endif
  }
}

LOCK 用于在多处理器中执行指令时对共享内存的独占使用。
它的作用是能够将当前处理器对应缓存的内容刷新到内存,并使其他处理器对应的缓存失效。

另外还提供了有序的指令无法越过这个内存屏障的作用。

上一篇下一篇

猜你喜欢

热点阅读