能演示下volatile为什么不保证原子性吗?
原子性:一个操作或一系列操作是不可分割的,要么同时成功,要么同时失败。
这个定义和volatile啥关系呀,完全不能理解呀?Show me the code!
考虑一下这种场景:
当20个线程同时给number自增1,执行1000次以后,number的值为多少呢?
在单线程的场景,答案是20000,如果是多线程的场景下呢?答案是可能是20000,但很多情况下都是小于20000。
示例代码:
package com.jackson0714.passjava.threads;
/**
演示volatile 不保证原子性
* @create: 2020-08-13 09:53
*/
public class VolatileAtomicity {
public static volatile int number = 0;
public static void increase() {
number++;
}
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
increase();
}
}, String.valueOf(i)).start();
}
// 当所有累加线程都结束
while(Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(number);
}
}
执行结果:第一次19144,第二次20000,第三次19378。



我们来分析一下increase()方法,通过反编译工具javap得到如下汇编代码:
public static void increase();
Code:
0: getstatic #2 // Field number:I
3: iconst_1
4: iadd
5: putstatic #2 // Field number:I
8: return
number++其实执行了3条指令:
getstatic:拿number的原始值 iadd:进行加1操作 putfield:把加1后的值写回
执行了getstatic指令number的值取到操作栈顶时,volatile关键字保证了number的值在此时是正确的,但是在执行iconst_1、iadd这些指令的时候,其他线程可能已经把number的值改变了,而操作栈顶的值就变成了过期的数据,所以putstatic指令执行后就可能把较小的number值同步回主内存之中。
总结如下:
在执行number++这行代码时,即使使用volatile修饰number变量,在执行期间,还是有可能被其他线程修改,没有保证原子性。
















