什么是 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技术。


相关文章
|
8月前
|
Java 编译器
解密Java多线程中的锁机制:CAS与Synchronized的工作原理及优化策略
解密Java多线程中的锁机制:CAS与Synchronized的工作原理及优化策略
|
3天前
|
Java 程序员 C++
Java中CAS详解
Java中CAS详解
7 0
|
4天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
12 0
|
4天前
|
算法 安全 Java
深入探索Java中的并发编程:CAS机制的原理与应用
总之,CAS机制是一种用于并发编程的原子操作,它通过比较内存中的值和预期值来实现多线程下的数据同步和互斥,从而提供了高效的并发控制。它在Java中被广泛应用于实现线程安全的数据结构和算法。
24 0
|
4天前
|
存储 安全 Java
【Java EE】CAS原理和实现以及JUC中常见的类的使用
【Java EE】CAS原理和实现以及JUC中常见的类的使用
|
9月前
|
安全 Java
《Java-SE-第二十八章》之CAS
《Java-SE-第二十八章》之CAS
|
6月前
|
Java
面试java并发~(lock、volatile、cas)
面试java并发~(lock、volatile、cas)
44 0
|
7月前
|
缓存 算法 安全
JUC第四讲:Java中的锁/CAS原理与案例分析(下)
JUC第四讲:Java中的锁/CAS原理与案例分析
|
7月前
|
缓存 安全 算法
JUC第四讲:Java中的锁/CAS原理与案例分析(上)
JUC第四讲:Java中的锁/CAS原理与案例分析
JUC第四讲:Java中的锁/CAS原理与案例分析(上)
|
8月前
|
安全 算法 Java
Java多线程(3)---锁策略、CAS和JUC
Java多线程(3)---锁策略、CAS和JUC
50 0