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 技术。