volatile 关键字不能保证原子性。它仅能保证可见性和禁止指令重排序,但无法确保复合操作的不可分割性(即原子性)。以下是详细分析:
为什么 volatile 无法保证原子性?
-
原子性的本质 原子性要求一个操作(如
i++)必须作为一个不可分割的整体执行,中间不能被其他线程中断。但i++实际包含三步:-
读取变量当前值(read)
-
计算新值(
i+1) -
写回新值(write)即使变量是volatile,多个线程仍可能在读与写之间发生干扰,导致数据竞争。
-
-
volatile 的作用边界
-
可见性:确保一个线程修改后,其他线程立即看到最新值(强制主内存读写)。
-
有序性:通过内存屏障禁止指令重排序(如单例模式的双重检查锁定)。但两者均不涉及操作过程的锁定机制,因此无法阻止多线程同时执行复合操作。
-
反例:volatile 修饰的计数器
public class VolatileExample {
private static volatile int count = 0;
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
count++; // 非原子操作!
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println("结果: " + count); // 可能小于 2000
}
}
原因: 若线程 A 和 B 同时读取 count=10,各自计算 11 后写回,最终结果变为 11 而非预期的 12

1012

被折叠的 条评论
为什么被折叠?



