Java中CAS的的简单了解和使用

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<Product> atomicReference = new AtomicReference<>(prudctor);
   static AtomicMarkableReference<Product> markableReference = new AtomicMarkableReference<>(prudctor,true);
    static AtomicStampedReference<Product> 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
        */
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值