CAS(Compare And Swap)比较并交换,是一个无锁算法,是一种乐观锁,采用cas可以实现线程安全问题,CAS一般有三个值,内存值,预期原值,新值,只有当内存值与预期原值相同的时候才能进行修改,如果不相同的时候,是无法进行修改操作的。
JUC包下的原子类操作全部是使用CAS实现的,包括并发容器,线程池等很多也采用CAS来保证原子性操作。
但是CAS也有几个问题:首先ABA问题,循环太久浪费资源,
ABA问题的解决方案,原之类包下提供了AtomicMarkableReference、AtomicStampedReference这两种类,一种是基于boolean,AtomicMarkableReference通过true或false来判断是否修改过(严格来讲该类并不能解决ABA问题,只是减低了几率,通过true/false来标记),而AtomicStampedReference是通过版本号机制来防止ABA问题,
class Test3 {
static Product prudctor = new Product(1,"zs");
static AtomicReference atomicReference = new AtomicReference<>(prudctor);
static AtomicMarkableReference markableReference = new AtomicMarkableReference<>(prudctor,true);
static AtomicStampedReference stampedReference = new AtomicStampedReference<>(prudctor,1);
public static void main(String[] args) {
//==============AtomicReference===================
// new Thread(()->{
// //获取内存值后,干活2秒,让线程B进行ABA操作
// Product product=atomicReference.get();
// System.out.println("线程B获取内存值:"+product);
// try {
// TimeUnit.MILLISECONDS.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("线程B在发生ABA问题是否能修改 atomicReference:"+atomicReference.compareAndSet(prudctor, new Product(3, "ww")));
// },"线程A").start();
// new Thread(()->{
// //在线程A干活的时候偷偷修改内存值
// atomicReference.compareAndSet(atomicReference.get(),new Product(2,"ww"));
// System.out.println("线程A,修改原内存值:"+atomicReference.get().toString());
// atomicReference.compareAndSet(atomicReference.get(),prudctor);
// System.out.println("线程A,进行aba后的值是否与原来值相同:"+atomicReference.get().equals(prudctor));
// }).start();
/**
* 输出结果
* 线程B获取内存值:Product{no=1, name='zs'}
* 线程A,修改原内存值:Product{no=2, name='ww'}
* 线程A,进行aba后的值是否与原来值相同:true
* 线程B在发生ABA问题是否能修改 atomicReference:true
*/
//================下面是AtomicMarkableReference======
new Thread(()->{
//获取原内存值后,干活3秒
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
Product reference = markableReference.getReference();
markableReference.compareAndSet(markableReference.getReference(), new Product(2, "ww"), false, true);
//再次修改为原内存值
System.out.println("线程B,进行ABA问题:"+markableReference.compareAndSet(markableReference.getReference(),reference, true, false));
},"线程B").start();
new Thread(()->{
//获取原内存值后,干活3秒
Product reference = markableReference.getReference();
System.out.println("线程A,获取原内存值:"+reference);
try {
TimeUnit.MILLISECONDS.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A,在发生ABA问题后是否能继续修改:"+
markableReference.compareAndSet(reference, new Product(2, "ww"), true, true));
},"线程A").start();
/**
* 输出结果
* 线程A,获取原内存值:Product{no=1, name='zs'}
* 线程B,进行ABA问题:true
* 线程A,在发生ABA问题后是否能继续修改:false
*/
//===============AtomicStamped===========
// new Thread(()->{
// //睡眠两秒让线程A获取stam
// Product reference = stampedReference.getReference();
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//// 进行ABA问题后看线程A能否修改
// System.out.println(stampedReference.compareAndSet(reference, new Product(2, "ww"), stampedReference.getStamp(), stampedReference.getStamp() + 1));
// //再次修改为原内存值
// System.out.println("线程B,进行ABA问题:"+stampedReference.compareAndSet(stampedReference.getReference(), reference, stampedReference.getStamp(), stampedReference.getStamp()+1));
// },"线程B").start();
// new Thread(()->{
// //获取原内存值后,干活3秒
// int stamp = stampedReference.getStamp();
// System.out.println("版本号:"+stamp);
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("线程A,在发生ABA问题后是否能继续修改:"+ stampedReference.compareAndSet(stampedReference.getReference(), new Product(2, "ww"),stamp,stamp+1));
// },"线程A").start();
/**
* 结果是不能修改
* 版本号:1
* true
* 线程B,进行ABA问题:true
* 线程A,在发生ABA问题后是否能继续修改:false
*/
}
}