简单来说就是原子类来实现CAS无锁模式的算法
java.util.concurrent.atomic包:是原子类的小工具包,支持在单个变量上解除锁的线程安全编程
原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读-改-写操作。
比如:AtomicInteger 表示一个int类型的值,并提供了 get 和 set 方法,这些 Volatile 类型的int
变量在读取和写入上有着相同的内存语义。它还提供了一个原子的 compareAndSet 方法(如果该
方法成功执行,那么将实现与读取/写入一个 volatile 变量相同的内存效果),以及原子的添加、
递增和递减等方法。AtomicInteger 表面上非常像一个扩展的 Counter 类,但在发生竞争的情况
下能提供更高的可伸缩性,因为它直接利用了硬件对并发的支持。
在 Java 中,java.util.concurrent.atomic 包提供了一系列原子类,旨在提供高效的线程安全操作。这些类使用了底层的 CAS(Compare-And-Swap)机制,允许多线程并发操作而不需要显式的同步。以下是对常见原子类的详细介绍,包括它们的使用场景、方法和底层机制
Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引 用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。
原子类的常用类
AtomicBoolean
AtomicInteger
AtomicLong
AtomicReference
Java 的 java.util.concurrent.atomic 包提供了一系列的原子类,用于实现无锁的线程安全操作。以下是常用的原子类及其区别:
常用的原子类
AtomicBoolean:
用于对 boolean 类型的变量进行原子操作。
常用于状态标志。
AtomicInteger:
用于对 int 类型的变量进行原子操作。
提供了原子递增、递减、加法等操作。
常用于计数器、并发 ID 生成器等。
AtomicLong:
用于对 long 类型的变量进行原子操作。
提供了与 AtomicInteger 类似的方法,只是操作的变量类型是 long。
AtomicReference:
用于对对象引用进行原子操作。
可以保存任意类型的对象引用。
AtomicStampedReference:
用于解决 AtomicReference 的 ABA 问题,通过给对象引用加上一个版本号(stamp)。
常用于需要检测对象是否发生过变化的场景。
AtomicMarkableReference:
类似于 AtomicStampedReference,但使用布尔标记而不是版本号。
适用于标记对象状态的场景。
AtomicIntegerArray:
用于对 int 数组的元素进行原子操作。
每个元素都可以独立地进行原子更新。
AtomicLongArray:
用于对 long 数组的元素进行原子操作。
提供了与 AtomicIntegerArray 类似的方法。
AtomicReferenceArray:
用于对对象数组的元素进行原子操作。
可以保存任意类型的对象引用数组。
区别
数据类型:
AtomicBoolean 处理 boolean 类型的变量。
AtomicInteger 处理 int 类型的变量。
AtomicLong 处理 long 类型的变量。
AtomicReference 处理任意类型的对象引用。
AtomicStampedReference 和 AtomicMarkableReference 处理对象引用并附带版本号或标记。
AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray 处理数组元素。
使用场景:
AtomicBoolean 常用于状态标志。
AtomicInteger 和 AtomicLong 常用于计数器、ID 生成器等。
AtomicReference 常用于需要原子更新引用的场景。
AtomicStampedReference 和 AtomicMarkableReference 用于解决 ABA 问题或标记对象状态。
AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray 用于需要对数组元素进行原子操作的场景。
示例代码
AtomicBoolean 示例
import java.util.concurrent.atomic.AtomicBoolean;
public class Task {
private AtomicBoolean running = new AtomicBoolean(false);
public void start() {
if (running.compareAndSet(false, true)) {
new Thread(this::run).start();
}
}
private void run() {
while (running.get()) {
// 执行任务
}
}
public void stop() {
running.set(false);
}
}
AtomicInteger 示例
import java.util.concurrent.atomic.AtomicInteger;
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
AtomicReference 示例
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceExample {
private static class Node {
int value;
Node next;
Node(int value) {
this.value = value;
}
}
private AtomicReference<Node> head = new AtomicReference<>();
public void push(int value) {
Node newNode = new Node(value);
Node oldHead;
do {
oldHead = head.get();
newNode.next = oldHead;
} while (!head.compareAndSet(oldHead, newNode));
}
public int pop() {
Node oldHead;
Node newHead;
do {
oldHead = head.get();
if (oldHead == null) {
throw new RuntimeException("Stack is empty");
}
newHead = oldHead.next;
} while (!head.compareAndSet(oldHead, newHead));
return oldHead.value;
}
}
AtomicStampedReference 示例
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampedReferenceExample {
private AtomicStampedReference<Integer> stampedRef = new AtomicStampedReference<>(0, 0);
public void update(int newValue) {
int[] stampHolder = new int[1];
Integer oldValue;
do {
oldValue = stampedRef.get(stampHolder);
} while (!stampedRef.compareAndSet(oldValue, newValue, stampHolder[0], stampHolder[0] + 1));
}
}
java.util.concurrent.atomic 包中的原子类提供了多种无锁的线程安全操作方式,适用于不同类型的数据和场景。选择适当的原子类可以帮助开发者编写高效且正确的并发程序。理解各个原子类的使用场景和区别,有助于在实际开发中灵活应用这些工具。