一、线程常见的 i++ 问题:使得i++ 循环执行20000次,最后打印出20000;
public class DemoCas {
int i = 0;
public void incr(){
i++;
}
public static void main(String[] args) {
DemoCas demo = new DemoCas();
for(int i =0;i<2;i++){
new Thread(()->{
for(int j=0;j<10000;j++){
demo.incr();
}
}).start();
}
try {
Thread.sleep(2000);
System.out.println("i="+demo.i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行结果:i是不定值,一般情况下会少于20000.
多线程的原子性:原子操作可以是一个步骤,也可以是多个操作步骤,但是顺序不能被打乱,也不可以被切割而只执行其中的一部分。将整个操作视为一个整体是原子性的核心特征。
执行i++操作会被分为三个步骤执行:
1、获取 i 的值
2、进行i+1
3、把i+1的值赋给i
CPU中的线程去获取i值进行操作时不满足原子性,两个线程获取的i值可能是相同的。因此程序执行的结果会少于20000;
解决办法:
1、加synchronized关键字
2、使用JUC中的atomic
3、使用Lock
二、CAS机制:compare and swap 比较和交换