The purpose of the volatile

1. Thread visibility

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; }}Copy the code

2. Prevent command reordering

Question: Do DCL singletons need volatile?

CPU basics

  • Disruptor: 64 bytes of cache line alignment is the basic unit for CPU synchronization. Cache line isolation can be more efficient than pseudo-sharing

    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); }}Copy the code

    MESI

  • False sharing

  • Merges writes 4 bytes of Buffer inside the CPU

    package com.mashibing.juc.c_029_WriteCombining;
    
    public final class WriteCombining {
    
        private static final int ITERATIONS = Integer.MAX_VALUE;
        private static final int ITEMS = 1 << 24;
        private static final int MASK = ITEMS - 1;
    
        private static final byte[] arrayA = new byte[ITEMS];
        private static final byte[] arrayB = new byte[ITEMS];
        private static final byte[] arrayC = new byte[ITEMS];
        private static final byte[] arrayD = new byte[ITEMS];
        private static final byte[] arrayE = new byte[ITEMS];
        private static final byte[] arrayF = new byte[ITEMS];
    
        public static void main(final String[] args) {
    
            for (int i = 1; i <= 3; i++) {
                System.out.println(i + " SingleLoop duration (ns) = " + runCaseOne());
                System.out.println(i + " SplitLoop duration (ns) = "+ runCaseTwo()); }}public static long runCaseOne(a) {
            long start = System.nanoTime();
            int i = ITERATIONS;
    
            while(--i ! =0) {
                int slot = i & MASK;
                byte b = (byte) i;
                arrayA[slot] = b;
                arrayB[slot] = b;
                arrayC[slot] = b;
                arrayD[slot] = b;
                arrayE[slot] = b;
                arrayF[slot] = b;
            }
            return System.nanoTime() - start;
        }
    
        public static long runCaseTwo(a) {
            long start = System.nanoTime();
            int i = ITERATIONS;
            while(--i ! =0) {
                int slot = i & MASK;
                byte b = (byte) i;
                arrayA[slot] = b;
                arrayB[slot] = b;
                arrayC[slot] = b;
            }
            i = ITERATIONS;
            while(--i ! =0) {
                int slot = i & MASK;
                byte b = (byte) i;
                arrayD[slot] = b;
                arrayE[slot] = b;
                arrayF[slot] = b;
            }
            returnSystem.nanoTime() - start; }}Copy the code
  • Instruction reordering

    package com.mashibing.jvm.c3_jmm;
    
    public class T04_Disorder {
        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;
            for(;;) {
                i++;
                x = 0; y = 0;
                a = 0; b = 0;
                Thread one = new Thread(new Runnable() {
                    public void run(a) {
                        // Since thread one starts first, wait for thread two. Readers can adjust the wait time according to the actual performance of their own computers.
                        //shortWait(100000);
                        a = 1; x = b; }}); Thread other =new Thread(new Runnable() {
                    public void run(a) {
                        b = 1; y = a; }}); one.start(); other.start(); one.join(); other.join(); String result ="The first" + i + "(" + x + "," + y + ")";
                if(x == 0 && y == 0) {
                    System.err.println(result);
                    break;
                } else {
                    //System.out.println(result);}}}public static void shortWait(long interval){
            long start = System.nanoTime();
            long end;
            do{
                end = System.nanoTime();
            }while(start + interval >= end); }}Copy the code

How does Volatile address instruction reordering

1: volatile i

2: ACC_VOLATILE

3: Memory barrier for the JVM

4: Hotspot implementation

bytecodeinterpreter.cpp

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

orderaccess_linux_x86.inline.hpp

inline void OrderAccess::fence(a) {
  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}}Copy the code