volatile的不保证原子性的证明
class MyData{
volatile int number;
public void increaseOne(){
this.number++;
}
}
public class Test {
public static void main(String[] args) {
MyData data = new MyData();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
new Thread(()->{
data.increaseOne();
},String.valueOf(i)).start();
}
}
//当其他线程执行完毕之后,再打印number的值
//java默认的后台线程为main线程和线程,所以当activeCount>2的时候,说明还有其他的线程没有执行完毕
while (Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(data.number);
}
}
控制台输出结果:
9996
//如果保证原子性,输出结果应该为100*100=10000
分析
class MyData{
volatile int number;
public void increaseOne(){
this.number++;
}
}
increaseOne的字节码指令
public void increaseOne();
Code:
0: aload_0 //从局部变量0中装载引用类型值
1: dup //复制栈顶部一个字长内容
2: getfield #2 // Field number:I 从对象中获取字段
5: iconst_1
6: iadd //进行加1操作
7: putfield #2 // Field number:I 设置对象中字段的值
10: return
线程A执行完iadd后还没来得及执行putfield,CPU调度时间片给线程B执行加一操作,而线程B加的数据还是原始的值,而不是A进行加一操作后的值,所以发生了写覆盖