关于volatile的可见性和禁止指令重排序的疑惑

时间:2023-03-08 21:50:47

在学习volatile语义的可见性和禁止指令重排序的相关测试中,发现并不能体现出禁止指令重排序的特性

实验代码如下

package com.aaron.beginner.multithread.volatiletest;

import java.util.concurrent.CountDownLatch;

/**
* @author
* @description 一句话描述该文件的用途
* @date 2017-03-01
*/
public class VolatileAndNonVolatileTest
{ private volatile boolean flag; private int num; public static void main(String[] args) throws InterruptedException
{ for (int i = 0; i < 5000; i++)
{
final VolatileAndNonVolatileTest test = new VolatileAndNonVolatileTest(); CountDownLatch latch = new CountDownLatch(2);
Thread write = new Thread(() ->
{
test.write();
latch.countDown();
}); Thread read = new Thread(() ->
{
test.read();
latch.countDown();
}); write.start();
read.start(); latch.await();
}
} private void read()
{
if (flag)
{
System.out.println("=" + num * num);
}
} private void write()
{
num = 10;//步骤1 flag = true;//步骤2 } }

实验步骤:

注意关注代码中flag变量,会分别测试flag变量有volatile修饰和没有volatile修饰时的输出情况

本测试代码主要的功能:

  1. write方法负责修改num变量,修改后设置flag=true,表示num变量已经修改成功
  2. read方法负责读取修改后的num值,并输入平方

实验步骤:

  1. 在循环中每次启动两个线程,一个线程负责调用write修改数据,另一个线程负责读取修改后的值
  2. 观察实验结构

预期结果:

  1. 当flag没有volatile修饰的时候,我们本应该期望的是能够输出"=100"
  2. 当flag有volatile修饰的时候,由于有可见性和禁止了指令重排序,每次正常输出"=100"

实际结果:

  1. 当flag没有volatile修饰的时候,多次实验均没有发现指令重排序发生(即出现"=0",也就是说write方法中步骤1和步骤2没有发生重排序(步骤2比步骤1先发生))
  2. 当flag有volatile修饰的时候(理论上有可见性和禁止了指令重排序,不会出现"=0"),实际上也没有出现"=0",和1结果一致。

  即加了和没加volatile的结果是一致的

试问各位大神,有知道怎么测试这个volatile,体现禁止了指令重排序的特点和可见性的特点吗?