证明 volatile 不具备原子性
假设一个简单场景:多个线程同时操作一个共享数据
public class AtomicTest {
public static volatile int count;
public static void main(String[] args) {
for (int i = 0; i < 500; i++) {
new Thread(()->{
AtomicTest.count++;
}).start();
}
/** 主线程等所有线程执行完,再去读取变量,3秒足够 */
ThreadUtils.threadSleep(3000);
System.out.println(AtomicTest.count);
}
}
多次运行后发现,结果基本都正确的理想值 500,因为每个线程运行的太快了。
但还是有可能会得到错误的值,放大这个可能性,修改:
// 让每个线程在操作数之前,都睡上10毫秒
ThreadUtils.threadSleep(10);
这样做的目的是,让多个线程都并行的效果
再运行,结构都是不同的错误值
其中,AtominTest.count++; 看起来只有一行代码,但它在字节码里可能需要多个指令来完成,在一个线程中的大致过程如下:
- 在方法去读取 count
- 压栈(每个线程都有它们独自的栈):把 count 压入栈顶
- 弹栈
- 加操作
- 把操作的结果值赋值给方法区的count
把这 5 个大致的操作看一个整体,当成原子性的操作,如果能保证多个线程遵循原子性的特性,那么结果是安全可靠的,
虽然volatile能保证 可见性 和 有序性,但它无法保证原子性,
每个线程都要执行上述的 5 个步骤,valatile 使得每个线程都在 主存中读写变量,并且按顺序执行操作步骤,但是多个线程一旦并行后,谁先做谁后做,就不能确定了
就是说,保证上述的原子性操作当前只有一个线程执行,完了后,再按序下一个线程来执行,synchronized 和 lock锁 不就是这么干的么🤔...

浙公网安备 33010602011771号