什么是 CAS?Java 中如何使用 CAS

简介: 什么是 CAS?Java 中如何使用 CAS

CAS是Compare And Swap(比较并交换)的缩写,是一种非阻塞式并发控制技术,用于保证多个线程在修改同一个共享资源时不会出现竞争条件,从而避免了传统锁机制的各种问题。在Java中,CAS主要是通过java.util.concurrent.atomic包下的一些类和方法来实现的,下面我们就来详细了解一下CAS及其在Java中的使用。


image.png


什么是CAS?


CAS是一种非阻塞式并发控制技术,它主要用于解决多个线程同时访问同一个共享资源时可能出现的竞争条件问题。为了保证数据的一致性和正确性,我们通常需要采取同步机制来对共享资源进行加锁。但是,传统的锁机制在高并发场景下会带来严重的性能问题,因为所有线程都需要等待锁的释放才能进行操作,这就会导致大量线程的阻塞和唤醒,进而降低了系统的并发性能。


为了解决这个问题,CAS应运而生。它是一种无锁的同步机制,可以在不使用锁的情况下实现数据的同步和并发控制。CAS的核心思想是:在执行操作之前,先比较当前内存中的值是否等于期望值,如果相等,则执行修改操作;如果不相等,则不执行修改操作,继续进行比较,直到内存中的值与期望值相等为止。这个过程中不会出现线程的阻塞和唤醒,因此可以提高系统的并发性能。


Java中的CAS


在Java中,CAS主要是通过java.util.concurrent.atomic包下的一些类和方法来实现的。这些类和方法提供了一种原子操作的方式,可以保证多个线程同时访问同一个共享资源时不会出现竞争条件。


AtomicBoolean


AtomicBoolean类表示一个布尔类型的原子变量,它提供了一些原子操作方法,例如compareAndSet、getAndSet、weakCompareAndSet等,可以保证对该变量的操作是原子的。


下面是一个示例代码:

import java.util.concurrent.atomic.AtomicBoolean;
public class AtomicBooleanTest {
    private static AtomicBoolean flag = new AtomicBoolean(false);
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (!flag.compareAndSet(false, true)) {
                System.out.println(Thread.currentThread().getName() + ": try again");
            }
            System.out.println(Thread.currentThread().getName() + ": success");
        },"Thread-1");
        Thread t2 = new Thread(() -> {
            while (!flag.compareAndSet(false, true)) {
                System.out.println(Thread.currentThread().getName() + ": try again");
            }
            System.out.println(Thread.currentThread().getName() + ": success");
        },"Thread-2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

在这个例子中,我们创建了一个AtomicBoolean类型的变量flag,并定义了两个线程t1和t2,它们都会不断地尝试将flag的值由false变为true,直到成功为止。如果两个线程同时尝试修改flag的值,只有一个线程能够获得成功,另一个线程会继续尝试,直到成功为止。


AtomicInteger


AtomicInteger类表示一个整型的原子变量,它提供了一些原子操作方法,例如compareAndSet、getAndSet、incrementAndGet等,可以保证对该变量的操作是原子的。


下面是一个示例代码:


import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerTest {
    private static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0;i < 10000; i++) {
                count.incrementAndGet();
            }
        },"Thread-1");
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                count.incrementAndGet();
            }
        },"Thread-2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("count = " + count.get());
    }
}

在这个例子中,我们创建了一个AtomicInteger类型的变量count,并定义了两个线程t1和t2,它们都会对count进行一万次的自增操作。由于AtomicInteger提供的incrementAndGet方法是原子的,因此多个线程同时对count进行自增操作不会出现竞争条件,最终count的值会是正确的。


AtomicReference


AtomicReference类表示一个引用类型的原子变量,它提供了一些原子操作方法,例如compareAndSet、getAndSet、weakCompareAndSet等,可以保证对该变量的操作是原子的。


下面是一个示例代码:


import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
    private static class Student{
        private String name;
        private int age;
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    private static AtomicReference<Student> student = new AtomicReference<>(new Student("张三", 18));
    public static void main(String[] args) {
        Student newStudent = new Student("李四", 20);
        student.compareAndSet(student.get(), newStudent);
        System.out.println(student.get());
    }
}

在这个例子中,我们创建了一个AtomicReference类型的变量student,并定义了一个Student类型的对象newStudent。我们通过compareAndSet方法将原子变量student的值从原来的Student对象修改为newStudent对象,由于AtomicReference提供的compareAndSet方法是原子的,因此多个线程同时对student进行修改操作不会出现竞争条件。


总结


CAS是一种非阻塞式的并发控制技术,它可以在不使用锁的情况下实现数据的同步和并发控制,从而提高系统的并发性能。在Java中,CAS主要是通过java.util.concurrent.atomic包下的一些类和方法来实现的,它们提供了一种原子操作的方式,可以保证多个线程同时访问同一个共享资源时不会出现竞争条件。在实际开发中,如果需要对共享资源进行并发控制,建议优先考虑使用CAS技术。


相关文章
|
2月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
3月前
|
安全 Java 调度
解锁Java并发编程高阶技能:深入剖析无锁CAS机制、揭秘魔法类Unsafe、精通原子包Atomic,打造高效并发应用
【8月更文挑战第4天】在Java并发编程中,无锁编程以高性能和低延迟应对高并发挑战。核心在于无锁CAS(Compare-And-Swap)机制,它基于硬件支持,确保原子性更新;Unsafe类提供底层内存操作,实现CAS;原子包java.util.concurrent.atomic封装了CAS操作,简化并发编程。通过`AtomicInteger`示例,展现了线程安全的自增操作,突显了这些技术在构建高效并发程序中的关键作用。
70 1
|
6月前
|
算法 安全 Java
Java多线程基础-12:详解CAS算法
CAS(Compare and Swap)算法是一种无锁同步原语,用于在多线程环境中更新内存位置的值。
69 0
|
4月前
|
安全 Oracle Java
(四)深入理解Java并发编程之无锁CAS机制、魔法类Unsafe、原子包Atomic
其实在我们上一篇文章阐述Java并发编程中synchronized关键字原理的时候我们曾多次谈到过CAS这个概念,那么它究竟是什么?
108 1
|
6月前
|
安全 Java 编译器
Java 多线程系列Ⅴ(常见锁策略+CAS+synchronized原理)
Java 多线程系列Ⅴ(常见锁策略+CAS+synchronized原理)
|
6月前
|
算法 Java
Java中CAS算法的集中体现:Atomic原子类库,你了解吗?
【5月更文挑战第15天】Java中CAS算法的集中体现:Atomic原子类库,你了解吗?
55 1
|
5月前
|
安全 Java
并发编程-Java如何实现原子操作(CAS或锁)
并发编程-Java如何实现原子操作(CAS或锁)
35 0
|
6月前
|
Java 程序员 C++
Java中CAS详解
Java中CAS详解
52 0
|
6月前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
63 0
|
6月前
|
算法 安全 Java
深入探索Java中的并发编程:CAS机制的原理与应用
总之,CAS机制是一种用于并发编程的原子操作,它通过比较内存中的值和预期值来实现多线程下的数据同步和互斥,从而提供了高效的并发控制。它在Java中被广泛应用于实现线程安全的数据结构和算法。
82 0