Juc15_基本AtomicInteger、数组、引用AtomicStampedReference、对象的属性修改原子类AtomicIntegerFieldUp 、原子操作增强类LongAdder(二)

简介: ③. 数组类型原子类 (AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray)④. 引用类型原子类 (AtomicReference、AtomicStampedReference、AtomicMarkableReference)

③. 数组类型原子类 (AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray)


  • ①. 数组类型原子类,主要有三个AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
    (了解即可)


  • ②. 代码展示


public class AtomicIntegerArrayDemo {
    public static void main(String[] args) {
        //(1). 创建一个新的AtomicIntegerArray,其长度与从给定数组复制的所有元素相同。
        int[]arr2={1,2,3,4,5};
        AtomicIntegerArray array=new AtomicIntegerArray(arr2);
        //(2). 创建给定长度的新AtomicIntegerArray,所有元素最初为零。
        //AtomicIntegerArray array=new AtomicIntegerArray(5);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        System.out.println();
        System.out.println("=======");
        array.getAndSet(0,1111);
        System.out.println("============");
        System.out.println("将数字中位置为0位置上的元素改为:"+array.get(0));
        System.out.println("数组位置为1位置上的旧值是:"+array.get(1));
        System.out.println("将数组位置为1位置上的数字进行加1的处理");
        array.getAndIncrement(1);
        System.out.println("数组位置为1位置上的新值是:"+array.get(1));
    }
}


④. 引用类型原子类 (AtomicReference、AtomicStampedReference、AtomicMarkableReference)


  • ①. 引用类型原子类主要有三个: AtomicReference、AtomicStampedReference、AtomicMark ableReference


  • ②. 使用AtomicReference来实现自旋锁案例


//自旋锁
public class AtomicReferenceThreadDemo {
    static AtomicReference<Thread>atomicReference=new AtomicReference<>();
    static Thread thread;
    public static void lock(){
        thread=Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"\t"+"coming.....");
        while(!atomicReference.compareAndSet(null,thread)){
        }
    }
    public static void unlock(){
        System.out.println(Thread.currentThread().getName()+"\t"+"over.....");
        atomicReference.compareAndSet(thread,null);
    }
    public static void main(String[] args) {
        new Thread(()->{
            AtomicReferenceThreadDemo.lock();
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            AtomicReferenceThreadDemo.unlock();
        },"A").start();
        new Thread(()->{
            AtomicReferenceThreadDemo.lock();
            AtomicReferenceThreadDemo.unlock();
        },"B").start();
    }
}


  • ③. AtomicStampedReference 解决ABA问题


  1. 携带版本号的引用类型原子类,可以解决ABA问题


  1. 解决修改过几次


  1. 状态戳原子引用


/**
 * Description: ABA问题的解决
 *
 * @author TANGZHI
 * @date 2021-03-26 21:30
 **/
public class ABADemo {
    private static AtomicReference<Integer> atomicReference=new AtomicReference<>(100);
    private static AtomicStampedReference<Integer> stampedReference=new AtomicStampedReference<>(100,1);
    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();
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("===以下是ABA问题的解决===");
        new Thread(()->{
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference());
            //暂停1秒钟t3线程
            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());
        },"t3").start();
        new Thread(()->{
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t 第1次版本号"+stamp+"\t值是"+stampedReference.getReference());
            //保证线程3完成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());
        },"t4").start();
    }



  • ④. AtomicMarkableReference 不建议用它解决ABA问题


  1. 原子更新带有标志位的引用类型对象


  1. 解决是否修改(它的定义就是将状态戳简化位true|false),类似一次性筷子


  1. 状态戳(true/false)原子引用


  1. 不建议用它解决ABA问题


public class ABADemo{
    static AtomicMarkableReference<Integer> markableReference = new AtomicMarkableReference<>(100,false);
    public static void main(String[] args){
        System.out.println("============AtomicMarkableReference不关心引用变量更改过几次,只关心是否更改过======================");
        new Thread(() -> {
            boolean marked = markableReference.isMarked();
            System.out.println(Thread.currentThread().getName()+"\t 1次版本号"+marked);
            try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
            markableReference.compareAndSet(100,101,marked,!marked);
            System.out.println(Thread.currentThread().getName()+"\t 2次版本号"+markableReference.isMarked());
            markableReference.compareAndSet(101,100,markableReference.isMarked(),!markableReference.isMarked());
            System.out.println(Thread.currentThread().getName()+"\t 3次版本号"+markableReference.isMarked());
        },"线程A").start();
        new Thread(() -> {
            boolean marked = markableReference.isMarked();
            System.out.println(Thread.currentThread().getName()+"\t 1次版本号"+marked);
            //暂停几秒钟线程
            try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
            markableReference.compareAndSet(100,2020,marked,!marked);
            System.out.println(Thread.currentThread().getName()+"\t"+markableReference.getReference()+"\t"+markableReference.isMarked());
        },"线程B").start();
    }
}


  • ⑤. AtomicStampedReference和AtomicMarkableReference区别


  1. stamped – version number 版本号,修改一次+1


  1. Markable – true、false 是否修改过
相关文章
|
安全 Java API
原子类型AtomicLong用法探究
AtomicLong 是 Java 提供的一个原子长整型类,提供了对长整型数据的原子性操作。在多线程环境下,AtomicLong 可以确保对长整型数据的操作是线程安全的。
285 0
|
6月前
|
Java 索引
JUC中的原子操作类及其原理
JUC中的原子操作类及其原理
|
7月前
|
存储 安全
除了Lock对象,还有其他方法可以实现多线程安全的单例模式吗?
【2月更文挑战第5天】【2月更文挑战第12篇】除了Lock对象,还有其他方法可以实现多线程安全的单例模式吗?
38 1
|
监控 安全 Java
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
自旋锁的伪代码实现,CAS的ABA问题,JUC常见类:Callable,ReentrantLock,线程创建方法的总结,信号量,原子类的应用场景,特定场所的组件CountDomLatch,针对集合类的
|
安全 Java API
原子操作类解读
原子操作类解读
原子操作类解读
|
算法 Java
第二季:3原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?【Java面试题】
第二季:3原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?【Java面试题】
107 0
|
安全 Java
变量的线程安全分析
变量的线程安全分析
|
安全 Java 编译器
多线程安全问题原理和解决办法Synchronized和ReentrantLock使用与区别
多线程安全问题原理和解决办法Synchronized和ReentrantLock使用与区别
|
安全
【多线程: 变量的线程安全分析】
【多线程: 变量的线程安全分析】
146 0
|
算法 NoSQL Java
AtomicInteger 底层实现原理是什么? 如何在自己代码中应用 CAS 操作
AtomicInteger 底层实现原理是什么? 如何在自己代码中应用 CAS 操作
219 0
AtomicInteger 底层实现原理是什么? 如何在自己代码中应用 CAS 操作