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