您当前的位置: 首页 >  Java

小志的博客

暂无认证

  • 2浏览

    0关注

    1217博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java并发多线程编程——原子类AtomicInteger的ABA问题及原子更新引用

小志的博客 发布时间:2022-01-10 23:05:07 ,浏览量:2

目录
    • 一、ABA问题的概述
    • 二、ABA问题的产生代码示例
    • 三、原子引用类(AtomicReference)
      • 3.1、jdk1.8 API中的原子引用类截图如下:
      • 3.2、原子引用类代码示例
    • 四、ABA问题的解决
      • 4.1、ABA问题的解决思路
      • 3.2、解决ABA问题的代码示例

一、ABA问题的概述
  • CAS会导致“ABA”问题。
  • CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当前时刻比较并替换,那么在这个时间差类会导致数据的变化。
  • 例如:一个线程 t1 从内存位置V中取出A,这个时候另一个线程 t2 也从内存中取出A,并且线程 t2 进行了一些操作将值变成了B,然后线程 t2 又将V位置的数据变成A,这时候线程t1 进行CAS操作发现内存中仍然是A,然后线程 t1 操作成功。
  • 尽管线程t1的CAS操作成功,但是不代表这个过程就是没有问题的。
二、ABA问题的产生代码示例
  • 代码

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicReference;
    /**
     * @description:  ABA问题的产生代码示例
     * @author: xz
     */
    public class ABADemo {
        private static AtomicReference atomicReference=new AtomicReference(100);
    
        public static void main(String[] args) {
            System.out.println("===以下是ABA问题的产生===");
            new Thread(()->{
                atomicReference.compareAndSet(100,101);
                atomicReference.compareAndSet(101,100);
            },"t1").start();
    
            new Thread(()->{
                //先暂停1秒 保证完成ABA
                try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println(atomicReference.compareAndSet(100, 2019)+"\t"+atomicReference.get());
            },"t2").start();
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

三、原子引用类(AtomicReference) 3.1、jdk1.8 API中的原子引用类截图如下:

在这里插入图片描述

3.2、原子引用类代码示例
  • 代码

    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * @description: 原子引用代码示例
     * @author: xz
     */
    @Getter
    @Setter
    @AllArgsConstructor
    @ToString
    class User{
        private String name;
        private int age;
    }
    
    public class AtomicReferenceDemo {
        public static void main(String[] args) {
    
            User zs = new User("张三", 29);
            User ls = new User("李四", 22);
    
            //AtomicReference中的泛型User表示原子引用类
            AtomicReference userAtomicReference = new AtomicReference();
            userAtomicReference.set(zs);
            //当期望的引用对象zs和主内存中的引用对象zs相同,修改为更新的ls引用对象
            System.out.println(userAtomicReference.compareAndSet(zs, ls)+"\t"+userAtomicReference.get().toString());
            //当期望的引用对象zs和主内存中的引用对象zs相同,修改为更新的ls引用对象
            System.out.println(userAtomicReference.compareAndSet(zs, ls)+"\t"+userAtomicReference.get().toString());
        }
    
    }
    
  • 输出结果如下: 在这里插入图片描述

四、ABA问题的解决 4.1、ABA问题的解决思路
  • jdk1.8 API中的时间戳原子引用类(AtomicStampedReference)截图如下: 在这里插入图片描述
3.2、解决ABA问题的代码示例
  • 代码

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicStampedReference;
    
    /**
     * @description:  通过AtomicStampedReference 时间戳原子引用类 解决ABA问题
     * @author: xz
     */
    public class ABADemo {
        private static AtomicStampedReference stampedReference=new AtomicStampedReference(100,1);
    
        public static void main(String[] args) {
            System.out.println("===以下是ABA问题的解决===");
    
            new Thread(()->{
                int stamp = stampedReference.getStamp();
                System.out.println(Thread.currentThread().getName()+
                        "\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference());
    
                //暂停1秒钟t1线程
                try { TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                stampedReference.compareAndSet(100,101,stampedReference.getStamp(),stampedReference.getStamp()+1);
                System.out.println(Thread.currentThread().getName()+"\t 第2次版本号"+stampedReference.getStamp()+"\t值是"+stampedReference.getReference());
    
                stampedReference.compareAndSet(101,100,stampedReference.getStamp(),stampedReference.getStamp()+1);
                System.out.println(Thread.currentThread().getName()+"\t 第3次版本号"+stampedReference.getStamp()+"\t值是"+stampedReference.getReference());
    
            },"t1").start();
    
            new Thread(()->{
                int stamp = stampedReference.getStamp();
                System.out.println(Thread.currentThread().getName()+
                        "\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference());
    
                //保证线程t1完成1次ABA
                try { TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                boolean result = stampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
                System.out.println(Thread.currentThread().getName()+"\t 修改成功否"+result+"\t最新版本号"+stampedReference.getStamp());
                System.out.println("最新的值\t"+stampedReference.getReference());
            },"t2").start();
    
        }
    }
    
  • 输出结果如下: 在这里插入图片描述

关注
打赏
1661269038
查看更多评论
立即登录/注册

微信扫码登录

0.0850s