我们直接给出含有一个bug的例子
创建两个线程,各执行5w次自增。正常情况,结果是10w。
初始代码如下:
package threading;
//线程不安全
class Counter{
private int count=0;
public void add(){
count++;
}
public int get(){
return count;
}
}
public class ThreadDemo10 {
public static void main(String[] args) throws InterruptedException{
Counter counter=new Counter();
//搞两个线程,两个线程分别对这个counter自增5w次
Thread t1=new Thread(()->{
for (int i = 0; i <50000 ; i++) {
counter.add();
}
});
t1.start();
Thread t2=new Thread(()-> {
for (int i = 0; i < 50000; i++) {
counter.add();
}
});
t2.start();
t1.join();
t2.join();
System.out.println(counter.get());
}
}
代码执行多次的结果
此时我们就奇怪了,为什对一个变量进行自增,结果的值不是我们想要的.
解释一下为啥会出现这种情况,和线程的调度随机性密切相关
count++操作,本质上是三个cpu指令的构成
1.load,把内存中的数据读取到cpu寄存器中
2.add,就是把寄存器中的值,进行+1运算
3.save,把寄存器中的值写回到内存中
由于多线程调度顺序是不确定的。实际执行过程中,这俩线程的++操作实际的指令排序顺序有很多种可能~
可能是以下这个样子(仅仅一部分):我们想要的是第2 或者 第3种
此处两个线程的指令的排序顺序有着很多种排列情况。
不同的排列顺序,结果是截然不同的。
我们简要分析一下过程,取最理想的情况我们分析一下
再来分析一下,随机的一种情况.
此时我们发现,两个线程自增两次,最后结果是1.其中一次自增的结果,被另一次覆盖了。
由于当前这两个线程调度顺序是无序的,有多少次是“顺序执行”,有多少次是“交错执行”是不知道的。
所以出现bug之后,得到的结果一定是<=10w。
结果是一定>=5w吗?
完全有可能小于5w,只是概率会小一些。