❎ 原子性

volatile 不是锁, 不保证原子性 错误代码示例:

public class Test {
    volatile int number = 0;
    public void increase() {
        number++;
    }
 
    public static void main(String[] args) {
        Test volatileAtomDemo = new Test();
        for (int j = 0; j < 10; j++) {
            new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
                    volatileAtomDemo.increase();
                }
            }, String.valueOf(j)).start();
        }
        while (Thread.activeCount() > 2) {
			// 暂停当前正在执行的线程,以允许其他线程获得执行机会,以此来提高并发竞争
            Thread.yield();
        }
 
        System.out.println(Thread.currentThread().getName() +
                           " final number result = " + volatileAtomDemo.number);
    }
}

✅ 可见性

  • 对volatile变量进行写操作的时候,JVM会向处理器发送一条lock前缀的指令,将这个缓存中的变量回写到系统主存中。
  • 如果一个变量被volatile所修饰的话,在每次数据变化之后,其值都会被强制刷入主存。

✅ 有序性

通过内存屏障来禁止指令重排 例子: 双重校验锁实现的单例

User a = new User(); 是原子性操作吗?

不是, 包含了3个步骤, 可能发生指令重排:

  1. 为User对象分配内存:JVM首先为新的User对象分配内存。
  2. 调用构造函数初始化对象:执行User类的构造函数来初始化对象。
  3. 引用赋值:将对象的内存引用赋给变量a。