1、什么是CAS?
compare and swap也就是比较和交换,他是一条CPU的并发原语。
他在替换内存的某个位置的值时,首先查看内存中的值与预期值是否一致,如果一致,执行替换操作。
这个操作是一个原子性操作。
Java中基于Unsafe的类提供了对CAS的操作的方法,JVM会帮助我们将方法实现CAS汇编指令但是要清楚CAS只是比较和交换,在获取原值的这个操作上,需要你自己实现。
public class AtomicIntegerTest {public static AtomicInteger atomicInteger = new AtomicInteger(0);public static void main(String[] args) {new Thread(() -> {for (int i = 0; i < 100; i++) {int i1 = atomicInteger.incrementAndGet();System.out.println(i1);}}).start();new Thread(() -> {for (int i = 0; i < 100; i++) {int i1 = atomicInteger.incrementAndGet();System.out.println(i1);}}).start();}
}
Doug Lea在CAS的基础上帮助我们实现了一些原子类,其中就包括现在看到的Atomicinteger,还有其他很多原子类.
CAS的缺点:CAS只能保证对一个变量的操作是原子性的,无法实现对多行代码实现原子性。
CAS的问题:
·ABA问题:问题如下,可以引入版本号的方式,来解决ABA的问题。Java中提供了一个类在CAS时,针对各个版本追加版本号的操作。AtomicStampeReference
初始值为str=A ,此时线程1修改str A 为B ,线程2修改str B为A ,此时线程3看到了还是A,但是此时的A已不是最初的那个A了,此时线程存在ABA问题。
public class AtomicInteger2Test {public static void main(String[] args) {//初始值AtomicReference<String> stringAtomicReference = new AtomicReference<>("A");//线程1进行修改new Thread(() -> {boolean b = stringAtomicReference.compareAndSet("A", "B");System.out.println(Thread.currentThread().getName() + ":" + b);System.out.println(Thread.currentThread().getName() + ":" + stringAtomicReference.get());}, "t1").start();//线程2进行修改new Thread(() -> {boolean b = stringAtomicReference.compareAndSet("B", "A");System.out.println(Thread.currentThread().getName() + ":" + b);System.out.println(Thread.currentThread().getName() + ":" + stringAtomicReference.get());}, "t2").start();//线程3进行修改new Thread(() -> {boolean b = stringAtomicReference.compareAndSet("A", "B");System.out.println(Thread.currentThread().getName() + ":" + b);System.out.println(Thread.currentThread().getName() + ":" + stringAtomicReference.get());},"t3").start();}
}
如何进行ABA问题的避免呢?
public class AtomicStampReferenceTest {public static void main(String[] args) {AtomicStampedReference<String> initVal = new AtomicStampedReference<String>("A",1);//线程1进行修改new Thread(()->{boolean b = initVal.compareAndSet("A", "B", 1, 2);System.out.println(Thread.currentThread().getName()+"线程修改结果:"+b);},"t1").start();//线程2进行修改new Thread(()->{boolean b = initVal.compareAndSet("B", "A", 2, 3);System.out.println(Thread.currentThread().getName()+"线程修改结果:"+b);},"t2").start();//线程3进行修改new Thread(()->{boolean b = initVal.compareAndSet("A", "B", 1, 2);System.out.println(Thread.currentThread().getName()+"线程修改结果:"+b);},"t3").start();}
}