原子操作就是: 不可中断的一个或者一系列操作, 也就是不会被线程调度机制打断的操作, 运行期间不会有任何的上下文切换
CAS:比较并交换(Compare and Swap)
解决方案:加版本号
ABA问题: 因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。
解决方案: 加版本号,在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。
为什么变成A,变成B又变回A?
因为是多线程,会互相覆盖,如t1对n进行+1,t2对n进行-1,执行期间互相覆盖就会出现这种情况,而且一个线程不知道其他线程对变量的操作。
自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。
概念: 当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。
CAS操作重大缺陷:【保证安全需要条件】
是写后读的锁,就是synchronized锁的写后读
例1代码:
//Demo2.java
public class Demo2 {public int num;public synchronized void add() {num++;}
}
//Test1.java
public class Test1 {public static void main(String[] args) throws Exception {Demo2 x =new Demo2();Thread t1 = new Thread() {@Overridepublic void run() {for(int i=0;i<10000;i++) {x.add();}}};Thread t2 = new Thread() {@Overridepublic void run() {for(int i=0;i<10000;i++) {x.add();}}};t1.start();t2.start();t1.join();t2.join();System.out.println(x.num);}
}
例2代码:
//Demo2.java
public class Demo2 {public int num;public synchronized int getnum() {return num;}public synchronized void setnum(int x) {num = x;}
}
//Test1.java
public class Test1 {public static void main(String[] args) throws Exception {Demo2 x =new Demo2();Thread t1 = new Thread() {@Overridepublic void run() {for(int i=0;i<10000;i++) {int a = x.getnum()+1;x.setnum(a);}}};Thread t2 = new Thread() {@Overridepublic void run() {for(int i=0;i<10000;i++) {int a = x.getnum()+1;x.setnum(a);}}};t1.start();t2.start();t1.join();t2.join();System.out.println(x.num);}
}
例3代码:
//Demo2.java
public class Demo2 {public int num;public synchronized int getnum() {return num;}public synchronized void setnum(int x) {num = x;}
}
//Test1.java
public class Test1 {public static void main(String[] args) throws Exception {Demo2 x =new Demo2();Thread t1 = new Thread() {@Overridepublic synchronized void run() {for(int i=0;i<10000;i++) {int a = x.getnum()+1;x.setnum(a);}}};Thread t2 = new Thread() {@Overridepublic synchronized void run() {for(int i=0;i<10000;i++) {int a = x.getnum()+1;x.setnum(a);}}};t1.start();t2.start();t1.join();t2.join();System.out.println(x.num);}
}