Interview question: Can volatile guarantee thread safety

Purpose

It is convenient for subsequent review by yourself, and it is also a record of learning.

resource

A learning video about high-frequency interview questions at Station B

How to understand thread safety

Reference: What is thread safety

3 aspects to consider in thread safety

visibility

One thread modifies the shared variable, another thread can see the latest result

orderliness

The code in a thread is executed in the order in which it was written, without the influence of instruction rearrangement

atomicity

Multiple lines of code in one thread run as a whole, during which no other thread's code can jump into the queue. There is no impact of thread switching.

Sample code verification

volatile does not guarantee atomicity

/**
 * volatile原子性例子: 不能保证原子性
 * <p>
 * 调试需要拆解"balance -= 5;" 使用Debug模式复现
 *
 * @author xiaozhengN [email protected]
 * @since 2022-11-19 18:09:41
 **/
@Slf4j
public class AddAndSubtract {
    
    

    static volatile int balance = 10;

    private static void subtract() {
    
    
        balance -= 5;
    }

    private static void add() {
    
    
        balance += 5;
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        CountDownLatch latch = new CountDownLatch(2);
        new Thread(() -> {
    
    
            subtract();
            latch.countDown();
        }).start();

        new Thread(() -> {
    
    
            add();
            latch.countDown();
        }).start();
        latch.await();
        log.info("共享变量balance: {}", balance);
    }
}

volatile guarantees visibility

/**
 * volatile 可见性例子
 *
 * -Xint
 *
 * @author xiaozhengN [email protected]
 * @since 2022-11-19 17:36:20
 **/
@Slf4j
public class ForeverLoop {
    
    

    // 共享变量, 控制 foo() 循环次数
    static volatile boolean isStop = false;

    public static void main(String[] args) {
    
    
        new Thread(() -> {
    
    
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                log.error("", e);
            }
            isStop = true;
            log.info("修改共享变量成功: isStop: {}", isStop);
        }).start();

        new Thread(() -> {
    
    
            try {
    
    
                Thread.sleep(200);
            } catch (InterruptedException e) {
    
    
                log.error("", e);
            }
            log.info("从主内存中获取共享变量, isStop: {}", isStop);
        }).start();
        foo();
    }

    static void foo() {
    
    
        int i = 0;
        while (!isStop) {
    
    
            i++;
        }
        log.info("foo方法已结束, 循环次数为: {}", i);
    }
}

volatile sets the memory barrier to ensure orderliness (difficult to understand)

/**
 * volatile 有序性例子
 * <p>
 * 没有测试成功, 报错: Unrecognized VM option 'StressCCP'
 * java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -jar jcstress.jar -t main.daily.Reordering.Case1
 * D:\17-JDKS\jdk-16.0.1\bin\java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -jar jcstress.jar -t main.daily.Reordering.Case1
 *
 * @author xiaozhengN [email protected]
 * @since 2022-11-19 18:27:03
 **/
public class Reordering {
    
    

    @JCStressTest
    @Outcome(id = {
    
    "0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
    @Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "感兴趣的值(发生指令重排)")
    @State
    public static class Case1 {
    
    
        int x;
        int y;

        @Actor
        public void actor1() {
    
    
            x = 1;
            y = 1;
        }

        @Actor
        public void actor2(II_Result result) {
    
    
            result.r1 = y;
            result.r2 = x;
        }
    }

    @JCStressTest
    @Outcome(id = {
    
    "0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
    @Outcome(id = "1, 0", expect = Expect.FORBIDDEN, desc = "被禁止的值")
    @State
    public static class Case2 {
    
    
        int x;
        volatile int y;

        @Actor
        public void actor1() {
    
    
            x = 1;
            y = 1;
        }

        @Actor
        public void actor2(II_Result result) {
    
    
            result.r1 = y;
            result.r2 = x;
        }
    }

    @JCStressTest
    @Outcome(id = {
    
    "0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
    @Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "感兴趣的值(发生指令重排)")
    @State
    public static class Case3 {
    
    
        volatile int x;
        int y;

        @Actor
        public void actor1() {
    
    
            x = 1;
            y = 1;
        }

        @Actor
        public void actor2(II_Result result) {
    
    
            result.r1 = y;
            result.r2 = x;
        }
    }
}

Guess you like

Origin blog.csdn.net/xiaozhengN/article/details/127947647