Juc并发编程10——原子类与ABA问题解决方案(下)

简介: 除了加锁以外,还可以使用原子类实现操作原子性。它底层采用CAS算法,使用简单、性能高效、线程安全

它还提供了lasySet方法,让你以普通变量而非volitile来操作数据,请读者自行了解。

除了基本数据类型有对应的原子类以外,基本的数组类型也有原子类。

演示如下

public class Demo27 {
    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerArray array = new AtomicIntegerArray(new int[]{0,3,5,9});
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000; i++) {
                    array.getAndAdd(0,1);
                }
                System.out.println("thread finish...");
            }
        };
        new Thread(r).start();
        new Thread(r).start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println(array.get(0));
    }
}

在jdk1.8以后,juc新增了LongAdderDoubleAdder,在高并发场景下,它的性能比AtomicLong,AtomicDouble会更好。

它的原理简单介绍如下。如下图,如果是多个线程对atomicLong进行操作,每次只能有一个线程成功CAS,而其它线程都会循环进行CAS直到成功。这样线程等待时间会随着等待队列变长而增加,时间性能不佳。但是LongAdder会自己维护一个cell[]数组,不同的线程都可以操作数组中的不同元素进行CAS,最后再进行求和累加,一次性更新value

使用实例如下

public class Demo28 {
    public static void main(String[] args) throws InterruptedException {
        LongAdder integer = new LongAdder();
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000; i++) {
                    integer.add(1);
                }
            }
        };
        for (int i = 0; i < 100; i++) {
            new Thread(r).start();
        }
        TimeUnit.SECONDS.sleep(1);
        System.out.println(integer.sum());
    }
}

除了对于基本数据类型有原子操作的支持外,对于引用类型,也可以实现原子操作

public class Demo29 {
    public static void main(String[] args) {
        String a = "hello a";
        String b = "hello b";
        AtomicReference<String> reference = new AtomicReference<>(a);
        reference.compareAndSet(a, b);
        System.out.println(reference.get());
    }
}

juc还提供了字段原子更新器,我们可以对于类中的某个字段进行原子的更新操作(注意字段必须使用vilotile关键字修饰)

public class Demo30 {
    public static void main(String[] args) {
        Student student = new Student();
        AtomicIntegerFieldUpdater<Student> updater = AtomicIntegerFieldUpdater.newUpdater(Student.class, "age");
        System.out.println(updater.incrementAndGet(student));
    }
    public static class Student{
        volatile int age;
    }
}

到目前为止,有关原子类的相关介绍结束了。现在我们想象下面的场景线程1,2同时CAS修改变量a的值,线程1速度较快,将a修改为2以后又把a修改为了1,这时线程2才开始判断,发现a的值就是expect的期望值1,于是CAS成功,将变量a修改为了2.很明显,这个时候的1与初始的1不是同一个1了,对于基本数据类型可能还不算太坏,但是对于string等这可不妙,这其实是CAS操作的一个问题,它只会机械的比较当前值是否与期望值一致,并不能知道当前值是否被修改过。这种问题就被称为ABA问题。


如何解决ABA问题呢,juc提供了带版本号的CAS操作,只要每次操作记录下版本号,并且版本号不重复就可以了

public class Demo31 {
    public static void main(String[] args) {
        String a = "hello a";
        String b = "hello a";
        AtomicStampedReference<String> reference = new AtomicStampedReference<>(a, 1);
        reference.attemptStamp(a,2);
        System.out.println(reference.compareAndSet(a, b, 2, 3));
    }
}


相关文章
|
8月前
|
缓存 Java 编译器
JUC 并发编程之JMM
Java内存模型是Java虚拟机(JVM)规范中定义的一组规则,用于屏蔽各种硬件和操作系统的内存访问差异,保证多线程情况下程序的正确执行。Java内存模型规定了线程之间如何交互以及线程和内存之间的关系。它主要解决的问题是可见性、原子性和有序性。
|
8月前
|
存储 安全 Java
剑指JUC原理-4.共享资源和线程安全性(上)
剑指JUC原理-4.共享资源和线程安全性
86 1
|
4月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
7月前
|
Java 索引
JUC中的原子操作类及其原理
JUC中的原子操作类及其原理
|
8月前
|
缓存 安全 Java
深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第27天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何在保证线程安全的前提下,通过合理使用锁机制来提升程序性能。我们将从基本的同步关键字出发,逐步介绍更高级的锁优化技术,包括可重入锁、读写锁以及乐观锁等,并配以实例代码来展示这些技术的应用。
|
8月前
|
安全 Java
JUC并发编程之原子类
并发编程是现代计算机应用中不可或缺的一部分,而在并发编程中,处理共享资源的并发访问是一个重要的问题。为了避免多线程访问共享资源时出现竞态条件(Race Condition)等问题,Java提供了一组原子类(Atomic Classes)来支持线程安全的操作。
|
8月前
|
缓存 算法 Java
JUC并发编程之CAS
CAS,即Compare and Swap,是一种并发编程中用于实现多线程环境下的原子操作的技术。它是一种无锁算法,用于解决多线程环境下的数据同步问题。CAS操作包含三个操作数:内存位置V,旧的预期值A和即将要写入的新值B。只有当内存位置的值与旧的预期值A相等时,才会将新值B写入内存位置V,否则不执行任何操作。CAS操作是原子的,保证了多线程环境下的数据一致性和线程安全性。
|
8月前
|
安全 Java Spring
剑指JUC原理-4.共享资源和线程安全性(下)
剑指JUC原理-4.共享资源和线程安全性
49 0
|
存储 SpringCloudAlibaba 安全
JUC并发编程(四):synchronized底层原理和锁升级优化
`synchronized`翻译过来是**同步**的意思,它是Java中一个关键字,是JVM层面提供的同步锁机制,用于保证多线程访问同一资源的可见性、互斥性。即当一个线程已经获取资源锁时,其他试图获取的线程只能等待或者阻塞在那里。
97 0
JUC并发编程(四):synchronized底层原理和锁升级优化
|
SpringCloudAlibaba 安全 Java
JUC并发编程(二):线程相关知识点
实现编发编程的主要手段就是多线程。线程是操作系统里的一个概念。接下来先说说两者的定义、联系与区别。
86 0