Java原子变量详解:AtomicInteger与CAS
Java原子变量详解:AtomicInteger与CAS
概述
原子变量是Java并发编程中的重要工具,它们提供了线程安全的操作,而无需使用锁。本教程介绍原子变量的使用和CAS(Compare-And-Swap)操作。
1. AtomicInteger
import java.util.concurrent.atomic.*;
public class AtomicIntegerExample {
public static void main(String[] args) throws InterruptedException {
AtomicInteger counter = new AtomicInteger(0);
// 基本操作
counter.set(10);
System.out.println("当前值: " + counter.get());
// 原子操作
counter.incrementAndGet(); // ++i
System.out.println("incrementAndGet: " + counter.get());
counter.getAndIncrement(); // i++
System.out.println("getAndIncrement: " + counter.get());
counter.addAndGet(5); // i += 5
System.out.println("addAndGet: " + counter.get());
// CAS操作
boolean success = counter.compareAndSet(16, 100);
System.out.println("CAS成功: " + success + ", 新值: " + counter.get());
// 并发测试
AtomicInteger atomicCounter = new AtomicInteger(0);
int threadCount = 10;
int incrementsPerThread = 10000;
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
atomicCounter.incrementAndGet();
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("并发计数: " + atomicCounter.get());
System.out.println("期望值: " + (threadCount * incrementsPerThread));
}
}
2. AtomicReference
import java.util.concurrent.atomic.*;
import java.util.function.*;
public class AtomicReferenceExample {
static class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}
public static void main(String[] args) {
AtomicReference<User> userRef = new AtomicReference<>(new User("Alice", 25));
System.out.println("初始用户: " + userRef.get());
// CAS更新
User oldUser = userRef.get();
User newUser = new User("Alice", 26);
userRef.compareAndSet(oldUser, newUser);
System.out.println("更新后: " + userRef.get());
// updateAndGet
userRef.updateAndGet(user -> {
user.age++;
return user;
});
System.out.println("updateAndGet: " + userRef.get());
// getAndUpdate
User previous = userRef.getAndUpdate(user -> {
user.name = "Bob";
return user;
});
System.out.println("前一个: " + previous);
System.out.println("当前: " + userRef.get());
}
}
3. AtomicStampedReference
import java.util.concurrent.atomic.*;
public class AtomicStampedReferenceExample {
public static void main(String[] args) {
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
// 获取值和版本号
int[] stampHolder = new int[1];
Integer value = ref.get(stampHolder);
int stamp = stampHolder[0];
System.out.println("值: " + value + ", 版本: " + stamp);
// CAS更新(需要值和版本号都匹配)
boolean success = ref.compareAndSet(100, 200, stamp, stamp + 1);
System.out.println("CAS成功: " + success);
value = ref.get(stampHolder);
System.out.println("更新后: " + value + ", 版本: " + stampHolder[0]);
}
}
4. 实际应用示例
线程安全的计数器
import java.util.concurrent.atomic.*;
public class ThreadSafeCounter {
private final AtomicInteger count = new AtomicInteger(0);
private final AtomicLong total = new AtomicLong(0);
public int increment() {
return count.incrementAndGet();
}
public int decrement() {
return count.decrementAndGet();
}
public int get() {
return count.get();
}
public void addToTotal(long value) {
total.addAndGet(value);
}
public long getTotal() {
return total.get();
}
public static void main(String[] args) throws InterruptedException {
ThreadSafeCounter counter = new ThreadSafeCounter();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
counter.addToTotal(1);
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("计数: " + counter.get());
System.out.println("总计: " + counter.getTotal());
}
}
线程安全的栈
import java.util.concurrent.atomic.*;
public class ConcurrentStack<E> {
private final AtomicReference<Node<E>> top = new AtomicReference<>();
private static class Node<E> {
final E data;
Node<E> next;
Node(E data) {
this.data = data;
}
}
public void push(E data) {
Node<E> newNode = new Node<>(data);
Node<E> currentTop;
do {
currentTop = top.get();
newNode.next = currentTop;
} while (!top.compareAndSet(currentTop, newNode));
}
public E pop() {
Node<E> currentTop;
Node<E> newTop;
do {
currentTop = top.get();
if (currentTop == null) {
return null;
}
newTop = currentTop.next;
} while (!top.compareAndSet(currentTop, newTop));
return currentTop.data;
}
public static void main(String[] args) {
ConcurrentStack<Integer> stack = new ConcurrentStack<>();
// 压栈
for (int i = 0; i < 10; i++) {
stack.push(i);
}
// 弹栈
Integer item;
while ((item = stack.pop()) != null) {
System.out.println("弹出: " + item);
}
}
}
5. 最佳实践
- 优先使用原子变量:比锁更轻量
- 使用CAS操作:原子更新操作
- 避免ABA问题:使用AtomicStampedReference
- 选择合适的类型:AtomicInteger、AtomicLong、AtomicReference等
- 注意性能:CAS在竞争激烈时性能下降
总结
原子变量是Java并发编程中的重要工具。掌握AtomicInteger、AtomicReference等的使用,可以编写高效的线程安全程序。在实际编程中,要根据需求选择合适的原子变量类型。