Java 原子类详解
原子类是Java并发包中提供的一组线程安全的工具类,它们基于CAS(Compare-And-Swap)操作实现,无需使用synchronized关键字。本文将详细介绍Java原子类的原理、使用方法和最佳实践。
本文内容概览
核心价值
原子类 = 无锁并发 + 高性能 + 线程安全性 + 简洁API + 内存可见性
- 🔄 无锁操作:基于CAS机制,避免传统锁带来的上下文切换开销
- 🚀 高性能:在低竞争环境下性能优于传统同步方式
- 🛡️ 线程安全:保证操作的原子性,避免并发问题
- 📊 精细控制:支持复杂的原子性条件更新操作
- 🔍 内存可见性:保证多线程间的数据一致性
1. 原子类概述
1.1 什么是原子类?
核心概念
原子类是基于CAS(Compare-And-Swap)操作实现的线程安全工具类,它们提供原子性的读写操作,无需使用传统的同步机制,具有高性能、无阻塞的特点。
1.2 CAS机制原理
CAS (Compare-And-Swap) 工作原理
CAS是一种无锁算法,其核心是一条CPU原子指令,执行过程如下:
- 比较(Compare):读取内存中当前值并与期望值比较
- 交换(Swap):如果当前值等于期望值,则将值更新为新值;否则不更新
- 返回结果:返回比较结果,表明操作是否成功
CAS操作包含三个参数:
- 内存位置V (Variable):要更新的变量
- 期望值A (Expected):预期当前值
- 新值B (New):要设置的新值
CAS操作保证了原子性:要么完全成功,要么完全失败,不会出现中间状态。
- CAS模拟实现
- CAS执行流程
- CAS优势
- CAS局限性
java
1public boolean compareAndSet(AtomicInteger value, int expect, int update) {2 // 这个方法是一个模拟,实际上CAS是由CPU原子指令实现的3 // 1. 读取当前值4 int current = value.get();5 6 // 2. 比较当前值与期望值7 if (current == expect) {8 // 3. 如果相等,则更新为新值9 value.set(update);10 return true;11 } else {12 // 4. 如果不相等,则更新失败13 return false;14 }15}1617// 使用CAS实现自旋锁18public void incrementUsingCAS(AtomicInteger value) {19 int oldValue;20 do {21 // 读取当前值22 oldValue = value.get();23 // 尝试CAS操作,直到成功24 } while (!value.compareAndSet(oldValue, oldValue + 1));25}- 避免锁开销:不需要获取和释放锁,减少线程上下文切换
- 高性能:在低竞争环境下,性能显著优于传统锁机制
- 无阻塞:线程可以立即知道更新是否成功,而不是被阻塞等待
- 避免死锁:不使用锁,因此不会出现死锁问题
- 适合读多写少:在读操作远多于写操作的场景下特别高效
- ABA问题:值从A变为B又变回A,CAS无法检测到这种变化
- 只能保证单个变量操作的原子性:不支持多个变量的原子性更新
- 自旋消耗CPU:CAS失败时通常会自旋重试,可能消耗较多CPU资源
- 高竞争下性能下降:当多个线程频繁争用同一变量时,CAS失败率高
1.3 原子类分类
Java原子类家族
- 基本类型原子类
- 引用类型原子类
- 数组类型原子类
- 字段更新器
包含类:
- AtomicInteger:原子整型,提供对int值的原子操作
- AtomicLong:原子长整型,提供对long值的原子操作
- AtomicBoolean:原子布尔型,提供对boolean值的原子操作
常用场景:
- 计数器
- 生成序列号
- 标志位控制
- 状态切换
包含类:
- AtomicReference
<V>:原子更新一个对象引用 - AtomicStampedReference
<V>:带有版本号的原子引用,解决ABA问题 - AtomicMarkableReference
<V>:带有标记的原子引用,用于标记引用是否被更新过
常用场景:
- 原子更新对象
- 解决CAS中的ABA问题
- 状态标记和版本控制
包含类:
- AtomicIntegerArray:原子整型数组,对int[]数组元素提供原子操作
- AtomicLongArray:原子长整型数组,对long[]数组元素提供原子操作
- AtomicReferenceArray:原子引用数组,对对象数组元素提供原子操作
常用场景:
- 并发计数器数组
- 状态数组
- 高并发环境下的数组更新
包含类:
- AtomicIntegerFieldUpdater:原子更新对象中int类型的字段
- AtomicLongFieldUpdater:原子更新对象中long类型的字段
- AtomicReferenceFieldUpdater:原子更新对象中引用类型的字段
常用场景:
- 避免创建额外的原子类实例
- 为已有类添加原子性操作
- 减少内存占用
限制条件:
- 字段必须是volatile修饰
- 字段必须是对更新器可访问的
- 类不能被加载器隐藏
2. 基本类型原子类
2.1 AtomicInteger
AtomicInteger核心API
| 方法 | 描述 | 等价同步代码 |
|---|---|---|
| get() | 获取当前值 | return value; |
| set(int) | 设置新值 | value = newValue; |
| getAndSet(int) | 设置新值并返回旧值 | int old = value; value = newValue; return old; |
| compareAndSet(int, int) | 比较并设置 | if(value==expect){value=update; return true;} else return false; |
| getAndIncrement() | 递增并返回旧值 | int old = value; value++; return old; |
| getAndDecrement() | 递减并返回旧值 | int old = value; value--; return old; |
| incrementAndGet() | 递增并返回新值 | return ++value; |
| decrementAndGet() | 递减并返回新值 | return --value; |
| getAndAdd(int) | 加上指定值并返回旧值 | int old = value; value += delta; return old; |
| addAndGet(int) | 加上指定值并返回新值 | value += delta; return value; |
| updateAndGet(IntUnaryOp) | 应用函数并返回新值 | value = updateFunction(value); return value; |
| getAndUpdate(IntUnaryOp) | 应用函数并返回旧值 | int old = value; value = updateFunction(value); return old; |
- 基本操作
- 高级操作
- 计数器示例
- 自旋CAS
java
1import java.util.concurrent.atomic.AtomicInteger;23// 创建AtomicInteger4AtomicInteger counter = new AtomicInteger(); // 默认值为05AtomicInteger initializedCounter = new AtomicInteger(100); // 初始值为10067// 获取当前值8int current = counter.get(); // 0910// 设置值11counter.set(50);12System.out.println(counter.get()); // 501314// 原子递增/递减15int prev = counter.getAndIncrement(); // 返回50,counter变为5116int next = counter.incrementAndGet(); // counter变为52,返回521718int prev2 = counter.getAndDecrement(); // 返回52,counter变为5119int next2 = counter.decrementAndGet(); // counter变为50,返回502021// 原子加法/减法22int beforeAdd = counter.getAndAdd(15); // 返回50,counter变为6523int afterAdd = counter.addAndGet(10); // counter变为75,返回752425// 比较并设置26boolean success = counter.compareAndSet(75, 100); // 如果当前值是75,则设为10027System.out.println(success + ", 当前值: " + counter.get()); // true, 当前值: 100java
1import java.util.concurrent.atomic.AtomicInteger;2import java.util.function.IntUnaryOperator;34AtomicInteger value = new AtomicInteger(10);56// 使用函数式接口更新7// 相当于:value = value * 28int doubled = value.updateAndGet(x -> x * 2); 9System.out.println(doubled); // 201011// 相当于:oldValue = value; value = value + 5; return oldValue;12int oldValue = value.getAndUpdate(x -> x + 5); 13System.out.println("旧值: " + oldValue + ", 新值: " + value.get()); // 旧值: 20, 新值: 251415// 累积操作16// 相当于:value = value + 3 * 217int result = value.accumulateAndGet(3, (x, y) -> x + y * 2);18System.out.println(result); // 31 (25 + 3*2)1920// 自定义函数21IntUnaryOperator powerOfTwo = x -> x * x;22int squared = value.updateAndGet(powerOfTwo);23System.out.println(squared); // 961 (31^2)java
1import java.util.concurrent.atomic.AtomicInteger;2import java.util.concurrent.ExecutorService;3import java.util.concurrent.Executors;4import java.util.concurrent.TimeUnit;56public class AtomicCounter {7 private final AtomicInteger count = new AtomicInteger(0);8 9 // 线程安全的增加方法10 public void increment() {11 count.incrementAndGet();12 }13 14 // 线程安全的获取方法15 public int getCount() {16 return count.get();17 }18 19 public static void main(String[] args) throws InterruptedException {20 final AtomicCounter counter = new AtomicCounter();21 ExecutorService executor = Executors.newFixedThreadPool(10);22 23 // 创建100个任务,每个任务增加计数器1000次24 for (int i = 0; i < 100; i++) {25 executor.submit(() -> {26 for (int j = 0; j < 1000; j++) {27 counter.increment();28 }29 });30 }31 32 // 关闭线程池并等待所有任务完成33 executor.shutdown();34 executor.awaitTermination(10, TimeUnit.SECONDS);35 36 // 输出最终计数,应该为100,00037 System.out.println("Final count: " + counter.getCount());38 }39}java
1import java.util.concurrent.atomic.AtomicInteger;23public class CASExample {4 private final AtomicInteger value = new AtomicInteger(0);5 6 // 使用CAS手动实现自旋递增7 public void incrementWithCAS() {8 int oldValue;9 int newValue;10 do {11 // 读取当前值12 oldValue = value.get();13 newValue = oldValue + 1;14 // 尝试CAS操作,失败则重试15 } while (!value.compareAndSet(oldValue, newValue));16 }17 18 // 条件更新 - 只有当值为偶数时才递增19 public boolean incrementIfEven() {20 while (true) {21 int current = value.get();22 if (current % 2 != 0) {23 return false; // 不是偶数,放弃操作24 }25 26 int next = current + 1;27 if (value.compareAndSet(current, next)) {28 return true; // CAS成功29 }30 // CAS失败,重试31 }32 }33}2.2 AtomicLong
AtomicLong特性
核心特点:
- 提供对long类型变量的原子操作
- 64位原子操作,解决在32位系统上long/double操作非原子性问题
- JDK 8后内部优化使用了CPU的CAS指令
- 高并发场景可考虑使用LongAdder替代以提高性能
应用场景:
- 全局序列号生成
- 大数量计数
- 高精度统计
- ID生成器
- 基本用法
- ID生成器
- 性能监控
java
1import java.util.concurrent.atomic.AtomicLong;23// 创建AtomicLong4AtomicLong counter = new AtomicLong(0); // 初始值为05AtomicLong idGenerator = new AtomicLong(1000); // 初始值为100067// 基本操作8long currentValue = counter.get(); // 获取当前值9counter.set(100); // 设置新值1011// 原子增减12long oldValue = counter.getAndIncrement(); // 返回0, counter变为113long newValue = counter.incrementAndGet(); // counter变为2, 返回21415// 原子更新16oldValue = counter.getAndAdd(10); // 返回2, counter变为1217newValue = counter.addAndGet(8); // counter变为20, 返回201819// CAS操作20boolean updated = counter.compareAndSet(20, 30); // true, counter变为30java
1import java.util.concurrent.atomic.AtomicLong;23/**4 * 简单的分布式ID生成器5 * - 支持多线程安全地生成唯一ID6 * - 可指定起始值和步长7 */8public class AtomicIdGenerator {9 private final AtomicLong sequenceNumber;10 private final String nodePrefix;11 private final int step;12 13 /**14 * 创建ID生成器15 * @param nodeId 节点ID (0-99)16 * @param startValue 起始值17 * @param step 步长18 */19 public AtomicIdGenerator(int nodeId, long startValue, int step) {20 // 保证节点ID为2位数字21 this.nodePrefix = String.format("%02d", nodeId % 100);22 this.sequenceNumber = new AtomicLong(startValue);23 this.step = step;24 }25 26 /**27 * 生成下一个ID28 * 格式: 节点前缀 + 当前时间戳 + 序列号29 */30 public String nextId() {31 long timestamp = System.currentTimeMillis();32 long sequence = sequenceNumber.getAndAdd(step);33 return nodePrefix + timestamp + sequence;34 }35 36 /**37 * 批量生成ID38 */39 public String[] batchIds(int batchSize) {40 String[] ids = new String[batchSize];41 for (int i = 0; i < batchSize; i++) {42 ids[i] = nextId();43 }44 return ids;45 }46 47 /**48 * 获取当前序列号49 */50 public long getCurrentSequence() {51 return sequenceNumber.get();52 }53 54 /**55 * 重置序列号56 */57 public void reset(long newValue) {58 sequenceNumber.set(newValue);59 }60}6162// 使用示例63AtomicIdGenerator idGen = new AtomicIdGenerator(1, 1000, 1);64String id1 = idGen.nextId();65String id2 = idGen.nextId();66System.out.println("ID1: " + id1);67System.out.println("ID2: " + id2);java
1import java.util.concurrent.atomic.AtomicLong;2import java.util.concurrent.TimeUnit;34/**5 * 高性能统计监控类6 */7public class PerformanceMonitor {8 private final AtomicLong requestCount = new AtomicLong(0);9 private final AtomicLong errorCount = new AtomicLong(0);10 private final AtomicLong totalResponseTime = new AtomicLong(0);11 private final AtomicLong minResponseTime = new AtomicLong(Long.MAX_VALUE);12 private final AtomicLong maxResponseTime = new AtomicLong(0);13 private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());14 15 /**16 * 记录请求17 */18 public void recordRequest(long responseTimeMs, boolean isSuccess) {19 requestCount.incrementAndGet();20 totalResponseTime.addAndGet(responseTimeMs);21 22 // 更新最小响应时间 (CAS自旋方式)23 while (true) {24 long currentMin = minResponseTime.get();25 if (responseTimeMs >= currentMin) break; // 当前值不是最小值26 if (minResponseTime.compareAndSet(currentMin, responseTimeMs)) break;27 }28 29 // 更新最大响应时间30 while (true) {31 long currentMax = maxResponseTime.get();32 if (responseTimeMs <= currentMax) break; // 当前值不是最大值33 if (maxResponseTime.compareAndSet(currentMax, responseTimeMs)) break;34 }35 36 if (!isSuccess) {37 errorCount.incrementAndGet();38 }39 }40 41 /**42 * 获取监控报告43 */44 public MonitorReport getReport() {45 long requests = requestCount.get();46 long errors = errorCount.get();47 long totalTime = totalResponseTime.get();48 long minTime = minResponseTime.get();49 long maxTime = maxResponseTime.get();50 long uptime = System.currentTimeMillis() - startTime.get();51 52 return new MonitorReport(53 requests,54 errors,55 requests > 0 ? totalTime / requests : 0,56 minTime == Long.MAX_VALUE ? 0 : minTime,57 maxTime,58 uptime59 );60 }61 62 /**63 * 重置统计数据64 */65 public void reset() {66 requestCount.set(0);67 errorCount.set(0);68 totalResponseTime.set(0);69 minResponseTime.set(Long.MAX_VALUE);70 maxResponseTime.set(0);71 startTime.set(System.currentTimeMillis());72 }73 74 public static class MonitorReport {75 public final long totalRequests;76 public final long errorRequests;77 public final long avgResponseTime;78 public final long minResponseTime;79 public final long maxResponseTime;80 public final long uptime;81 82 public MonitorReport(83 long totalRequests, long errorRequests, 84 long avgResponseTime, long minResponseTime, 85 long maxResponseTime, long uptime) {86 this.totalRequests = totalRequests;87 this.errorRequests = errorRequests;88 this.avgResponseTime = avgResponseTime;89 this.minResponseTime = minResponseTime;90 this.maxResponseTime = maxResponseTime;91 this.uptime = uptime;92 }93 94 @Override95 public String toString() {96 return String.format(97 "请求总数: %d, 错误: %d (%.2f%%), 平均响应时间: %dms, " +98 "最小: %dms, 最大: %dms, 运行时间: %ds",99 totalRequests,100 errorRequests,101 totalRequests > 0 ? (errorRequests * 100.0 / totalRequests) : 0.0,102 avgResponseTime,103 minResponseTime,104 maxResponseTime,105 TimeUnit.MILLISECONDS.toSeconds(uptime)106 );107 }108 }109}2.3 AtomicBoolean
AtomicBoolean特性与应用
主要特点:
- 原子性地更新boolean类型值
- 适合状态标志和开关控制场景
- 线程安全的初始化标记
- 原子开关操作
常用方法:
get(): 获取当前值set(boolean): 设置新值getAndSet(boolean): 设置新值并返回旧值compareAndSet(boolean, boolean): 比较并设置
典型应用场景:
- 一次性操作标志
- 服务开关控制
- 线程安全的初始化
- 状态标记
- 基本使用
- 一次性操作
- 熔断器实现
java
1import java.util.concurrent.atomic.AtomicBoolean;23// 创建AtomicBoolean,默认false4AtomicBoolean flag = new AtomicBoolean();56// 创建带初始值的AtomicBoolean7AtomicBoolean enabledFlag = new AtomicBoolean(true);89// 获取当前值10boolean isEnabled = enabledFlag.get(); // true1112// 设置新值13enabledFlag.set(false);1415// 原子地获取旧值并设置新值16boolean oldValue = enabledFlag.getAndSet(true);17System.out.println("旧值: " + oldValue + ", 新值: " + enabledFlag.get());18// 输出: 旧值: false, 新值: true1920// CAS操作21boolean wasUpdated = enabledFlag.compareAndSet(true, false);22System.out.println("更新成功: " + wasUpdated + ", 当前值: " + enabledFlag.get());23// 输出: 更新成功: true, 当前值: falsejava
1import java.util.concurrent.atomic.AtomicBoolean;2import java.util.concurrent.ExecutorService;3import java.util.concurrent.Executors;45/**6 * 使用AtomicBoolean确保某操作只执行一次7 */8public class OneTimeAction {9 private final AtomicBoolean initialized = new AtomicBoolean(false);10 11 /**12 * 确保只初始化一次13 */14 public void initialize() {15 // compareAndSet方法原子性地检查和更新值,确保只有一个线程可以执行初始化16 if (initialized.compareAndSet(false, true)) {17 try {18 System.out.println("执行初始化操作 - 由线程 " + 19 Thread.currentThread().getName());20 21 // 模拟耗时的初始化操作22 Thread.sleep(1000);23 24 System.out.println("初始化完成");25 } catch (InterruptedException e) {26 // 如果初始化失败,重置标志27 initialized.set(false);28 Thread.currentThread().interrupt();29 }30 } else {31 System.out.println("已初始化 - 线程 " + 32 Thread.currentThread().getName() + " 跳过");33 }34 }35 36 /**37 * 检查是否已初始化38 */39 public boolean isInitialized() {40 return initialized.get();41 }42 43 /**44 * 重置初始化状态45 */46 public void reset() {47 initialized.set(false);48 }49 50 public static void main(String[] args) {51 final OneTimeAction action = new OneTimeAction();52 ExecutorService executor = Executors.newFixedThreadPool(5);53 54 // 多个线程同时尝试初始化55 for (int i = 0; i < 10; i++) {56 executor.submit(action::initialize);57 }58 59 executor.shutdown();60 }61}java
1import java.util.concurrent.atomic.AtomicBoolean;2import java.util.concurrent.atomic.AtomicInteger;3import java.util.concurrent.atomic.AtomicLong;45/**6 * 简单的熔断器实现7 */8public class CircuitBreaker {9 private final AtomicBoolean open = new AtomicBoolean(false);10 private final AtomicInteger failureCount = new AtomicInteger(0);11 private final AtomicLong lastFailureTime = new AtomicLong(0);12 13 private final int failureThreshold;14 private final long resetTimeoutMs;15 16 public CircuitBreaker(int failureThreshold, long resetTimeoutMs) {17 this.failureThreshold = failureThreshold;18 this.resetTimeoutMs = resetTimeoutMs;19 }20 21 /**22 * 检查熔断器是否打开23 */24 public boolean isOpen() {25 // 已经打开的情况下,检查是否可以尝试关闭26 if (open.get()) {27 // 超过重置时间后允许尝试恢复28 long currentTime = System.currentTimeMillis();29 if (currentTime - lastFailureTime.get() > resetTimeoutMs) {30 // 重置为关闭状态(半开状态)31 open.compareAndSet(true, false);32 return false;33 }34 return true;35 }36 return false;37 }38 39 /**40 * 记录成功41 */42 public void recordSuccess() {43 // 成功后重置失败计数44 failureCount.set(0);45 // 如果处于半开状态,确保关闭熔断器46 open.set(false);47 }48 49 /**50 * 记录失败51 */52 public void recordFailure() {53 // 记录最后失败时间54 lastFailureTime.set(System.currentTimeMillis());55 56 // 增加失败计数57 int currentFailures = failureCount.incrementAndGet();58 59 // 如果达到阈值,打开熔断器60 if (currentFailures >= failureThreshold) {61 open.set(true);62 }63 }64 65 /**66 * 执行受保护的代码67 */68 public <T> T execute(Supplier<T> supplier, T fallback) {69 if (isOpen()) {70 // 熔断器打开,直接返回降级结果71 return fallback;72 }73 74 try {75 // 尝试执行操作76 T result = supplier.get();77 recordSuccess();78 return result;79 } catch (Exception e) {80 recordFailure();81 return fallback;82 }83 }84 85 // 简单的Supplier接口86 public interface Supplier<T> {87 T get() throws Exception;88 }89}3. 引用类型原子类
引用类型原子类概述
引用类型原子类用于原子性地更新对象引用,主要包括以下几个类:
- AtomicReference:原子更新一个对象引用
- AtomicStampedReference:带有版本号的原子引用,解决ABA问题
- AtomicMarkableReference:带有标记的原子引用,用于标记引用是否被更新过
这些类使得在不使用锁的情况下,安全地更新对象引用成为可能,特别适合于实现无锁数据结构和算法。
3.1 AtomicReference
- 基本用法
- 对象引用
- 状态管理
java
1import java.util.concurrent.atomic.AtomicReference;23// 创建带初始值的AtomicReference4AtomicReference<String> atomicString = new AtomicReference<>("初始值");56// 创建空的AtomicReference7AtomicReference<User> atomicUser = new AtomicReference<>();89// 获取引用10String value = atomicString.get();11System.out.println("当前值: " + value); // 当前值: 初始值1213// 设置新值14atomicString.set("新值");15System.out.println("更新后: " + atomicString.get()); // 更新后: 新值1617// 原子方式获取并设置18String oldValue = atomicString.getAndSet("更新的值");19System.out.println("旧值: " + oldValue + ", 当前值: " + atomicString.get());20// 输出: 旧值: 新值, 当前值: 更新的值2122// 比较并设置23boolean wasUpdated = atomicString.compareAndSet("更新的值", "最终值");24System.out.println("更新是否成功: " + wasUpdated + ", 当前值: " + atomicString.get());25// 输出: 更新是否成功: true, 当前值: 最终值2627// 使用函数更新28atomicString.updateAndGet(current -> current + " - 附加内容");29System.out.println("函数更新后: " + atomicString.get());30// 输出: 函数更新后: 最终值 - 附加内容java
1import java.util.concurrent.atomic.AtomicReference;23class User {4 private final String name;5 private final int age;6 7 public User(String name, int age) {8 this.name = name;9 this.age = age;10 }11 12 public User withAge(int newAge) {13 return new User(this.name, newAge);14 }15 16 @Override17 public String toString() {18 return "User{name='" + name + "', age=" + age + "}";19 }20}2122// 创建一个用户的原子引用23AtomicReference<User> userRef = new AtomicReference<>(new User("张三", 20));2425// 打印当前用户26System.out.println("当前用户: " + userRef.get());2728// 原子地更新用户年龄 - 使用CAS操作29User user;30User newUser;31do {32 user = userRef.get();33 newUser = user.withAge(user.age + 1);34} while (!userRef.compareAndSet(user, newUser));3536System.out.println("更新后用户: " + userRef.get());3738// 使用函数式更新39userRef.updateAndGet(u -> u.withAge(u.age + 5));40System.out.println("函数更新后: " + userRef.get());java
1import java.util.concurrent.atomic.AtomicReference;2import java.util.concurrent.TimeUnit;3import java.util.concurrent.ExecutorService;4import java.util.concurrent.Executors;56/**7 * 使用AtomicReference实现状态机8 */9public class StateMachine {10 // 定义可能的状态11 public enum State {12 INITIALIZING, RUNNING, PAUSED, SHUTTING_DOWN, TERMINATED13 }14 15 private final AtomicReference<State> state = 16 new AtomicReference<>(State.INITIALIZING);17 18 /**19 * 尝试转换状态20 * @param from 期望的当前状态21 * @param to 目标状态22 * @return 是否转换成功23 */24 public boolean transitionState(State from, State to) {25 return state.compareAndSet(from, to);26 }27 28 /**29 * 获取当前状态30 */31 public State getState() {32 return state.get();33 }34 35 public static void main(String[] args) throws InterruptedException {36 StateMachine machine = new StateMachine();37 ExecutorService executor = Executors.newFixedThreadPool(2);38 39 // 任务1: 初始化后运行40 executor.submit(() -> {41 if (machine.transitionState(State.INITIALIZING, State.RUNNING)) {42 System.out.println("成功启动!");43 } else {44 System.out.println("启动失败!");45 }46 });47 48 // 给任务1一点时间执行49 TimeUnit.MILLISECONDS.sleep(100);50 51 // 任务2: 尝试暂停52 executor.submit(() -> {53 if (machine.transitionState(State.RUNNING, State.PAUSED)) {54 System.out.println("成功暂停!");55 } else {56 System.out.println("暂停失败!");57 }58 });59 60 executor.shutdown();61 }62}3.2 AtomicStampedReference
ABA 问题与解决方案
ABA问题是指:
- 线程1读取共享变量的值为A
- 线程2将共享变量的值修改为B,然后又修改回A
- 线程1进行CAS操作,发现共享变量的值仍为A,认为没有被修改过,但实际上已经经历了 A→B→A 的变化
AtomicStampedReference通过添加版本号解决ABA问题:
- 每次更新引用的同时更新版本号
- CAS操作同时检查引用和版本号
- 即使引用值相同,若版本号不同,CAS操作也会失败
- 基本用法
- ABA问题解决示例
- 版本控制
java
1import java.util.concurrent.atomic.AtomicStampedReference;23// 创建AtomicStampedReference,初始引用为"A",初始版本号为14AtomicStampedReference<String> asr = 5 new AtomicStampedReference<>("A", 1);67// 读取当前引用和版本号8int[] stampHolder = new int[1];9String value = asr.get(stampHolder);10int stamp = stampHolder[0];1112System.out.println("初始值: " + value + ", 版本号: " + stamp);1314// 更新引用和版本号15boolean success = asr.compareAndSet("A", "B", stamp, stamp + 1);16System.out.println("更新结果: " + success);1718// 再次获取新的引用和版本号19value = asr.get(stampHolder);20stamp = stampHolder[0];21System.out.println("更新后值: " + value + ", 版本号: " + stamp);2223// 尝试使用过期版本号更新,将会失败24boolean outdatedSuccess = asr.compareAndSet("B", "C", 1, 2);25System.out.println("使用旧版本号更新结果: " + outdatedSuccess);2627// 使用当前版本号更新,将会成功28boolean currentSuccess = asr.compareAndSet("B", "C", stamp, stamp + 1);29System.out.println("使用当前版本号更新结果: " + currentSuccess);30System.out.println("最终值: " + asr.getReference() + ", 版本号: " + asr.getStamp());java
1import java.util.concurrent.atomic.AtomicStampedReference;2import java.util.concurrent.TimeUnit;34/**5 * 使用AtomicStampedReference解决ABA问题的示例6 */7public class ABAProblemSolution {8 private static final AtomicStampedReference<Integer> atomicStampedRef = 9 new AtomicStampedReference<>(100, 0);1011 public static void main(String[] args) throws InterruptedException {12 System.out.println("===== ABA问题解决示例 =====");13 14 // 获取初始的版本号15 int initialStamp = atomicStampedRef.getStamp();16 Integer initialRef = atomicStampedRef.getReference();17 System.out.println("初始值: " + initialRef + ", 初始版本: " + initialStamp);18 19 // 线程1 - 模拟解决ABA问题20 Thread t1 = new Thread(() -> {21 System.out.println("线程1:读取初始值和版本号");22 int stamp = atomicStampedRef.getStamp();23 Integer ref = atomicStampedRef.getReference();24 25 try {26 // 线程1暂停1秒,让线程2完成ABA操作27 TimeUnit.SECONDS.sleep(1);28 } catch (InterruptedException e) {29 Thread.currentThread().interrupt();30 }31 32 System.out.println("线程1:尝试更新 100 -> 101, 版本:" + stamp + " -> " + (stamp + 1));33 boolean success = atomicStampedRef.compareAndSet(34 100, 101, stamp, stamp + 1);35 36 System.out.println("线程1:CAS " + (success ? "成功" : "失败") + 37 ", 当前值: " + atomicStampedRef.getReference() + 38 ", 当前版本: " + atomicStampedRef.getStamp());39 });40 41 // 线程2 - 模拟造成ABA问题的操作42 Thread t2 = new Thread(() -> {43 try {44 // 让线程1先运行并读取值45 TimeUnit.MILLISECONDS.sleep(100);46 } catch (InterruptedException e) {47 Thread.currentThread().interrupt();48 }49 50 int stamp = atomicStampedRef.getStamp();51 System.out.println("线程2:当前版本 " + stamp);52 53 // 100 -> 200 -> 100,制造ABA54 System.out.println("线程2:100 -> 200");55 atomicStampedRef.compareAndSet(100, 200, stamp, stamp + 1);56 57 System.out.println("线程2:当前版本 " + atomicStampedRef.getStamp());58 59 // 再改回10060 System.out.println("线程2:200 -> 100");61 atomicStampedRef.compareAndSet(200, 100, 62 atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);63 64 System.out.println("线程2:当前版本 " + atomicStampedRef.getStamp());65 });66 67 t1.start();68 t2.start();69 70 t1.join();71 t2.join();72 73 System.out.println("最终值: " + atomicStampedRef.getReference() + 74 ", 最终版本: " + atomicStampedRef.getStamp());75 }76}java
1import java.util.concurrent.atomic.AtomicStampedReference;2import java.util.concurrent.ConcurrentHashMap;34/**5 * 使用AtomicStampedReference实现简单的版本控制缓存6 */7public class VersionedCache<K, V> {8 private static class VersionedValue<V> {9 final V value;10 final long timestamp;11 12 VersionedValue(V value, long timestamp) {13 this.value = value;14 this.timestamp = timestamp;15 }16 17 @Override18 public String toString() {19 return value + " (v" + timestamp + ")";20 }21 }22 23 private final ConcurrentHashMap<K, AtomicStampedReference<VersionedValue<V>>> cache = 24 new ConcurrentHashMap<>();25 26 /**27 * 获取缓存值,返回值和版本号28 */29 public V get(K key, int[] versionHolder) {30 AtomicStampedReference<VersionedValue<V>> ref = cache.get(key);31 if (ref == null) {32 versionHolder[0] = 0;33 return null;34 }35 36 VersionedValue<V> versionedValue = ref.get(versionHolder);37 return versionedValue != null ? versionedValue.value : null;38 }39 40 /**41 * 更新缓存,仅当版本号匹配时42 * @return 是否更新成功43 */44 public boolean put(K key, V value, int expectedVersion) {45 long timestamp = System.currentTimeMillis();46 VersionedValue<V> newVersionedValue = new VersionedValue<>(value, timestamp);47 48 AtomicStampedReference<VersionedValue<V>> ref = cache.get(key);49 if (ref == null) {50 if (expectedVersion != 0) {51 return false; // 期望有版本号,但实际不存在52 }53 // 首次创建,版本为154 ref = new AtomicStampedReference<>(newVersionedValue, 1);55 AtomicStampedReference<VersionedValue<V>> existing = 56 cache.putIfAbsent(key, ref);57 return existing == null;58 }59 60 // 更新现有值,版本号加161 return ref.compareAndSet(62 ref.getReference(), newVersionedValue, expectedVersion, expectedVersion + 1);63 }64 65 /**66 * 删除缓存67 * @return 是否删除成功68 */69 public boolean remove(K key, int expectedVersion) {70 AtomicStampedReference<VersionedValue<V>> ref = cache.get(key);71 if (ref == null) {72 return false;73 }74 75 int[] stampHolder = new int[1];76 ref.get(stampHolder);77 78 if (stampHolder[0] != expectedVersion) {79 return false; // 版本不匹配80 }81 82 return cache.remove(key, ref);83 }84 85 /**86 * 获取当前键值数量87 */88 public int size() {89 return cache.size();90 }91}3.3 AtomicMarkableReference
AtomicMarkableReference与AtomicStampedReference的对比
| 特性 | AtomicMarkableReference | AtomicStampedReference |
|---|---|---|
| 标记类型 | 布尔值(标记/未标记) | 整数(版本号) |
| 内存占用 | 较小 | 较大 |
| 适用场景 | 只需要标记对象是否被修改过 | 需要完整的版本历史 |
| 解决ABA | 部分解决(只能检测到是否有过修改) | 完全解决(通过版本号区分) |
| API复杂度 | 较简单 | 较复杂 |
- 基本用法
- 逻辑删除
java
1import java.util.concurrent.atomic.AtomicMarkableReference;23// 创建AtomicMarkableReference,初始引用为"数据",初始标记为false4AtomicMarkableReference<String> amr = 5 new AtomicMarkableReference<>("数据", false);67// 获取当前值和标记8boolean[] markHolder = new boolean[1];9String value = amr.get(markHolder);10boolean mark = markHolder[0];1112System.out.println("初始值: " + value + ", 标记: " + mark);1314// 更新引用并设置标记15boolean success = amr.compareAndSet("数据", "新数据", false, true);16System.out.println("更新结果: " + success);1718// 再次获取值和标记19value = amr.get(markHolder);20mark = markHolder[0];21System.out.println("更新后值: " + value + ", 标记: " + mark);2223// 仅更新标记,不更新引用24success = amr.attemptMark("新数据", false);25System.out.println("仅更新标记结果: " + success);26System.out.println("标记更新后: " + amr.isMarked());java
1import java.util.concurrent.atomic.AtomicMarkableReference;23/**4 * 使用AtomicMarkableReference实现链表节点的逻辑删除5 */6public class LogicalDeletionExample {7 static class Node {8 String item;9 Node next;10 11 public Node(String item) {12 this.item = item;13 }14 15 @Override16 public String toString() {17 return item;18 }19 }20 21 /**22 * 链表节点的包装,带有逻辑删除标记23 */24 static class MarkedNode {25 private final AtomicMarkableReference<Node> reference;26 27 public MarkedNode(Node node) {28 this.reference = new AtomicMarkableReference<>(node, false);29 }30 31 /**32 * 获取节点(如果未被逻辑删除)33 */34 public Node get() {35 boolean[] marked = new boolean[1];36 Node node = reference.get(marked);37 return marked[0] ? null : node; // 如果已标记删除,返回null38 }39 40 /**41 * 逻辑删除节点42 */43 public boolean delete() {44 boolean[] marked = new boolean[1];45 Node node = reference.get(marked);46 47 if (marked[0]) {48 return false; // 已经被删除49 }50 51 // 标记为已删除52 return reference.compareAndSet(node, node, false, true);53 }54 55 /**56 * 检查是否已删除57 */58 public boolean isDeleted() {59 return reference.isMarked();60 }61 62 /**63 * 恢复删除的节点(取消删除标记)64 */65 public boolean undelete() {66 boolean[] marked = new boolean[1];67 Node node = reference.get(marked);68 69 if (!marked[0]) {70 return false; // 没有被删除,无需恢复71 }72 73 // 取消删除标记74 return reference.compareAndSet(node, node, true, false);75 }76 77 /**78 * 更新节点(如果未被删除)79 */80 public boolean updateIfNotDeleted(Node newNode) {81 boolean[] marked = new boolean[1];82 Node oldNode = reference.get(marked);83 84 if (marked[0]) {85 return false; // 已被删除,不能更新86 }87 88 return reference.compareAndSet(oldNode, newNode, false, false);89 }90 }91 92 public static void main(String[] args) {93 Node node = new Node("节点1");94 MarkedNode markedNode = new MarkedNode(node);95 96 System.out.println("初始节点: " + markedNode.get());97 System.out.println("已删除? " + markedNode.isDeleted());98 99 // 逻辑删除节点100 boolean deleted = markedNode.delete();101 System.out.println("删除成功? " + deleted);102 System.out.println("已删除? " + markedNode.isDeleted());103 System.out.println("获取节点: " + markedNode.get());104 105 // 尝试更新已删除的节点106 boolean updated = markedNode.updateIfNotDeleted(new Node("节点2"));107 System.out.println("更新成功? " + updated);108 109 // 恢复节点110 boolean undeleted = markedNode.undelete();111 System.out.println("恢复成功? " + undeleted);112 System.out.println("已删除? " + markedNode.isDeleted());113 System.out.println("获取节点: " + markedNode.get());114 115 // 更新已恢复的节点116 updated = markedNode.updateIfNotDeleted(new Node("节点2"));117 System.out.println("更新成功? " + updated);118 System.out.println("更新后节点: " + markedNode.get());119 }120}4. 数组原子类
数组原子类概述
数组原子类提供对数组元素的原子操作,主要包括:
- AtomicIntegerArray:原子更新整型数组里的元素
- AtomicLongArray:原子更新长整型数组里的元素
- AtomicReferenceArray:原子更新引用类型数组里的元素
数组原子类保证对数组中每个元素的操作都是原子性的,但不保证对整个数组的操作是原子性的。
4.1 AtomicIntegerArray
- 基本操作
- 批量操作
- 计数器数组示例
- 位图实现
java
1import java.util.concurrent.atomic.AtomicIntegerArray;23// 创建AtomicIntegerArray4AtomicIntegerArray array = new AtomicIntegerArray(5); // 默认值为05AtomicIntegerArray initializedArray = new AtomicIntegerArray(new int[]{1, 2, 3, 4, 5}); // 初始值67// 获取元素8int value = array.get(0); // 09System.out.println("array[0]: " + value);1011// 设置元素12array.set(0, 10);13System.out.println("array[0] after set: " + array.get(0)); // 101415// 原子递增/递减16int prev = array.getAndIncrement(1); // 返回2, array[1]变为317int next = array.incrementAndGet(1); // array[1]变为4, 返回41819prev = array.getAndDecrement(1); // 返回4, array[1]变为320next = array.decrementAndGet(1); // array[1]变为2, 返回22122// 原子加法/减法23prev = array.getAndAdd(2, 15); // 返回3, array[2]变为1824next = array.addAndGet(2, 10); // array[2]变为28, 返回282526// 比较并设置27boolean success = array.compareAndSet(2, 28, 30); // 如果当前值是28,则设为3028System.out.println("CAS成功: " + success + ", array[2]: " + array.get(2)); // true, array[2]: 30java
1import java.util.concurrent.atomic.AtomicIntegerArray;23// 创建AtomicIntegerArray4AtomicIntegerArray array = new AtomicIntegerArray(5);56// 批量递增7array.getAndAdd(0, 10); // array[0]变为108array.getAndAdd(1, 20); // array[1]变为209array.getAndAdd(2, 30); // array[2]变为301011// 批量递减12array.getAndDecrement(3); // array[3]变为-113array.getAndDecrement(4); // array[4]变为-21415// 批量加法16array.addAndGet(0, 5); // array[0]变为1517array.addAndGet(1, 10); // array[1]变为3018array.addAndGet(2, 15); // array[2]变为451920// 批量比较并设置21boolean[] successFlags = new boolean[5];22successFlags[0] = array.compareAndSet(0, 15, 20); // false23successFlags[1] = array.compareAndSet(1, 30, 35); // true24successFlags[2] = array.compareAndSet(2, 45, 50); // true25successFlags[3] = array.compareAndSet(3, -1, 0); // true26successFlags[4] = array.compareAndSet(4, -2, -3); // true2728System.out.println("批量操作后数组: " + array);29for (int i = 0; i < successFlags.length; i++) {30 System.out.println("array[" + i + "] CAS成功: " + successFlags[i]);31}java
1import java.util.concurrent.atomic.AtomicIntegerArray;2import java.util.concurrent.ExecutorService;3import java.util.concurrent.Executors;4import java.util.concurrent.TimeUnit;56/**7 * 使用AtomicIntegerArray实现并发计数器数组8 */9public class AtomicCounterArray {10 private final AtomicIntegerArray counters;11 12 public AtomicCounterArray(int size) {13 this.counters = new AtomicIntegerArray(size);14 }15 16 /**17 * 递增指定索引的计数器18 */19 public void increment(int index) {20 counters.incrementAndGet(index);21 }22 23 /**24 * 获取指定索引的计数器值25 */26 public int get(int index) {27 return counters.get(index);28 }29 30 /**31 * 批量递增多个计数器32 */33 public void batchIncrement(int[] indices, int increment) {34 for (int i : indices) {35 counters.addAndGet(i, increment);36 }37 }38 39 /**40 * 批量获取多个计数器值41 */42 public int[] getBatch(int[] indices) {43 int[] values = new int[indices.length];44 for (int i = 0; i < indices.length; i++) {45 values[i] = counters.get(indices[i]);46 }47 return values;48 }49 50 /**51 * 重置指定索引的计数器52 */53 public void reset(int index) {54 counters.set(index, 0);55 }56 57 /**58 * 批量重置多个计数器59 */60 public void resetBatch(int[] indices) {61 for (int i : indices) {62 counters.set(i, 0);63 }64 }65 66 public static void main(String[] args) throws InterruptedException {67 final AtomicCounterArray counterArray = new AtomicCounterArray(10);68 ExecutorService executor = Executors.newFixedThreadPool(10);69 70 // 创建10个任务,每个任务递增数组中10个随机索引的计数器1000次71 for (int i = 0; i < 10; i++) {72 executor.submit(() -> {73 int[] indices = new int[10];74 for (int j = 0; j < indices.length; j++) {75 indices[j] = (int) (Math.random() * 10); // 随机索引76 }77 for (int k = 0; k < 1000; k++) {78 counterArray.increment(indices[k % indices.length]); // 递增随机索引79 }80 });81 }82 83 executor.shutdown();84 executor.awaitTermination(10, TimeUnit.SECONDS);85 86 // 输出最终计数87 System.out.println("最终计数数组: " + Arrays.toString(counterArray.getBatch(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})));88 }89}java
1import java.util.concurrent.atomic.AtomicIntegerArray;2import java.util.Arrays;34/**5 * 使用AtomicIntegerArray实现位图6 */7public class AtomicBitmap {8 private final AtomicIntegerArray bits;9 private final int size;10 11 public AtomicBitmap(int size) {12 this.size = size;13 // 确保数组大小是32的倍数,或者向上取整14 this.bits = new AtomicIntegerArray((size + 31) / 32 * 32);15 }16 17 /**18 * 设置位19 */20 public void set(int index) {21 if (index < 0 || index >= size) {22 throw new IndexOutOfBoundsException("Index out of bounds: " + index);23 }24 25 int arrayIndex = index / 32;26 int bitIndex = index % 32;27 int mask = 1 << bitIndex;28 29 while (true) {30 int current = bits.get(arrayIndex);31 int updated = current | mask;32 if (bits.compareAndSet(arrayIndex, current, updated)) {33 break;34 }35 }36 }37 38 /**39 * 清除位40 */41 public void clear(int index) {42 if (index < 0 || index >= size) {43 throw new IndexOutOfBoundsException("Index out of bounds: " + index);44 }45 46 int arrayIndex = index / 32;47 int bitIndex = index % 32;48 int mask = ~(1 << bitIndex);49 50 while (true) {51 int current = bits.get(arrayIndex);52 int updated = current & mask;53 if (bits.compareAndSet(arrayIndex, current, updated)) {54 break;55 }56 }57 }58 59 /**60 * 获取位61 */62 public boolean get(int index) {63 if (index < 0 || index >= size) {64 throw new IndexOutOfBoundsException("Index out of bounds: " + index);65 }66 67 int arrayIndex = index / 32;68 int bitIndex = index % 32;69 int mask = 1 << bitIndex;70 71 return (bits.get(arrayIndex) & mask) != 0;72 }73 74 /**75 * 获取位图大小76 */77 public int size() {78 return size;79 }80 81 /**82 * 获取位图数组83 */84 public AtomicIntegerArray getBits() {85 return bits;86 }87 88 @Override89 public String toString() {90 StringBuilder sb = new StringBuilder();91 for (int i = 0; i < size; i++) {92 sb.append(get(i) ? 1 : 0);93 if ((i + 1) % 8 == 0) sb.append(" ");94 if ((i + 1) % 32 == 0) sb.append("\n");95 }96 return sb.toString();97 }98}5. 字段更新器
5.1 字段更新器概述
字段更新器允许原子性地更新对象的volatile字段,无需将整个对象声明为原子类。
- 基本使用
- 示例
- 限制条件
java
1import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;2import java.util.concurrent.atomic.AtomicLongFieldUpdater;3import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;45// 假设有一个类需要原子更新其int字段6public class AtomicFieldUpdaterExample {7 public static class Counter {8 public volatile int count = 0;9 10 // 使用AtomicIntegerFieldUpdater11 private static final AtomicIntegerFieldUpdater<Counter> UPDATER =12 AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");13 14 public void increment() {15 UPDATER.incrementAndGet(this);16 }17 18 public int getCount() {19 return UPDATER.get(this);20 }21 22 public boolean compareAndSet(int expect, int update) {23 return UPDATER.compareAndSet(this, expect, update);24 }25 }26 27 public static void main(String[] args) {28 Counter counter = new Counter();29 30 // 多个线程同时递增计数器31 for (int i = 0; i < 10; i++) {32 new Thread(() -> {33 for (int j = 0; j < 1000; j++) {34 counter.increment();35 }36 }).start();37 }38 39 try {40 Thread.sleep(1000); // 等待所有线程完成41 } catch (InterruptedException e) {42 Thread.currentThread().interrupt();43 }44 45 System.out.println("最终计数: " + counter.getCount());46 }47}java
1import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;2import java.util.concurrent.atomic.AtomicLongFieldUpdater;3import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;45// 假设有一个类需要原子更新其int字段6public class AtomicFieldUpdaterExample {7 public static class Counter {8 public volatile int count = 0;9 10 // 使用AtomicIntegerFieldUpdater11 private static final AtomicIntegerFieldUpdater<Counter> UPDATER =12 AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");13 14 public void increment() {15 UPDATER.incrementAndGet(this);16 }17 18 public int getCount() {19 return UPDATER.get(this);20 }21 22 public boolean compareAndSet(int expect, int update) {23 return UPDATER.compareAndSet(this, expect, update);24 }25 }26 27 public static void main(String[] args) {28 Counter counter = new Counter();29 30 // 多个线程同时递增计数器31 for (int i = 0; i < 10; i++) {32 new Thread(() -> {33 for (int j = 0; j < 1000; j++) {34 counter.increment();35 }36 }).start();37 }38 39 try {40 Thread.sleep(1000); // 等待所有线程完成41 } catch (InterruptedException e) {42 Thread.currentThread().interrupt();43 }44 45 System.out.println("最终计数: " + counter.getCount());46 }47}java
1import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;2import java.util.concurrent.atomic.AtomicLongFieldUpdater;3import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;45// 假设有一个类需要原子更新其int字段6public class AtomicFieldUpdaterExample {7 public static class Counter {8 public volatile int count = 0;9 10 // 使用AtomicIntegerFieldUpdater11 private static final AtomicIntegerFieldUpdater<Counter> UPDATER =12 AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");13 14 public void increment() {15 UPDATER.incrementAndGet(this);16 }17 18 public int getCount() {19 return UPDATER.get(this);20 }21 22 public boolean compareAndSet(int expect, int update) {23 return UPDATER.compareAndSet(this, expect, update);24 }25 }26 27 public static void main(String[] args) {28 Counter counter = new Counter();29 30 // 多个线程同时递增计数器31 for (int i = 0; i < 10; i++) {32 new Thread(() -> {33 for (int j = 0; j < 1000; j++) {34 counter.increment();35 }36 }).start();37 }38 39 try {40 Thread.sleep(1000); // 等待所有线程完成41 } catch (InterruptedException e) {42 Thread.currentThread().interrupt();43 }44 45 System.out.println("最终计数: " + counter.getCount());46 }47}6. 原子类最佳实践
6.1 使用建议
核心原则
使用原子类时需要考虑以下因素:
- 性能要求:原子类适合高并发、低竞争场景
- 功能需求:根据具体需求选择合适的原子类
- ABA问题:需要版本控制时使用AtomicStampedReference
- 内存开销:原子类比普通变量占用更多内存
6.2 性能优化
- 基本优化
- 性能优化
- 常见陷阱
java
1import java.util.concurrent.atomic.AtomicInteger;23public class AtomicClassOptimization {4 private final AtomicInteger counter = new AtomicInteger(0);5 6 /**7 * 减少CAS失败8 */9 public void optimizedIncrement() {10 while (true) {11 int current = counter.get();12 int next = current + 1;13 if (counter.compareAndSet(current, next)) {14 break;15 }16 // 可以添加退避策略17 Thread.yield();18 }19 }20 21 /**22 * 避免过度使用23 */24 public static class AvoidOveruse {25 // 不推荐:过度使用原子类26 private final AtomicInteger x = new AtomicInteger(0);27 private final AtomicInteger y = new AtomicInteger(0);28 private final AtomicInteger z = new AtomicInteger(0);29 30 // 推荐:使用复合对象31 public static class Point {32 private volatile int x, y, z;33 34 public synchronized void setCoordinates(int x, int y, int z) {35 this.x = x;36 this.y = y;37 this.z = z;38 }39 40 public synchronized int[] getCoordinates() {41 return new int[]{x, y, z};42 }43 }44 }45}java
1import java.util.concurrent.atomic.AtomicInteger;2import java.util.concurrent.atomic.AtomicLong;3import java.util.concurrent.atomic.AtomicBoolean;4import java.util.concurrent.atomic.AtomicReference;5import java.util.concurrent.atomic.AtomicStampedReference;6import java.util.concurrent.atomic.AtomicMarkableReference;7import java.util.concurrent.atomic.AtomicIntegerArray;8import java.util.concurrent.atomic.AtomicLongArray;9import java.util.concurrent.atomic.AtomicReferenceArray;10import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;11import java.util.concurrent.atomic.AtomicLongFieldUpdater;12import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;1314public class AtomicClassOptimization {15 private final AtomicInteger counter = new AtomicInteger(0);16 private final AtomicLong longCounter = new AtomicLong(0);17 private final AtomicBoolean booleanFlag = new AtomicBoolean(false);18 private final AtomicReference<String> stringRef = new AtomicReference<>("initial");19 private final AtomicStampedReference<String> stampedRef = new AtomicStampedReference<>("A", 0);20 private final AtomicMarkableReference<String> markableRef = new AtomicMarkableReference<>("data", false);21 private final AtomicIntegerArray intArray = new AtomicIntegerArray(5);22 private final AtomicLongArray longArray = new AtomicLongArray(5);23 private final AtomicReferenceArray<String> refArray = new AtomicReferenceArray<>(5);24 private final AtomicIntegerFieldUpdater<AtomicClassOptimization> intUpdater =25 AtomicIntegerFieldUpdater.newUpdater(AtomicClassOptimization.class, "counter");26 private final AtomicLongFieldUpdater<AtomicClassOptimization> longUpdater =27 AtomicLongFieldUpdater.newUpdater(AtomicClassOptimization.class, "longCounter");28 private final AtomicReferenceFieldUpdater<AtomicClassOptimization, String> refUpdater =29 AtomicReferenceFieldUpdater.newUpdater(AtomicClassOptimization.class, String.class, "stringRef");30 31 /**32 * 减少CAS失败33 */34 public void optimizedIncrement() {35 while (true) {36 int current = counter.get();37 int next = current + 1;38 if (counter.compareAndSet(current, next)) {39 break;40 }41 // 可以添加退避策略42 Thread.yield();43 }44 }45 46 /**47 * 避免过度使用48 */49 public static class AvoidOveruse {50 // 不推荐:过度使用原子类51 private final AtomicInteger x = new AtomicInteger(0);52 private final AtomicInteger y = new AtomicInteger(0);53 private final AtomicInteger z = new AtomicInteger(0);54 55 // 推荐:使用复合对象56 public static class Point {57 private volatile int x, y, z;58 59 public synchronized void setCoordinates(int x, int y, int z) {60 this.x = x;61 this.y = y;62 this.z = z;63 }64 65 public synchronized int[] getCoordinates() {66 return new int[]{x, y, z};67 }68 }69 }70}java
1import java.util.concurrent.atomic.AtomicInteger;2import java.util.concurrent.atomic.AtomicLong;3import java.util.concurrent.atomic.AtomicBoolean;4import java.util.concurrent.atomic.AtomicReference;5import java.util.concurrent.atomic.AtomicStampedReference;6import java.util.concurrent.atomic.AtomicMarkableReference;7import java.util.concurrent.atomic.AtomicIntegerArray;8import java.util.concurrent.atomic.AtomicLongArray;9import java.util.concurrent.atomic.AtomicReferenceArray;10import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;11import java.util.concurrent.atomic.AtomicLongFieldUpdater;12import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;1314public class AtomicClassOptimization {15 private final AtomicInteger counter = new AtomicInteger(0);16 private final AtomicLong longCounter = new AtomicLong(0);17 private final AtomicBoolean booleanFlag = new AtomicBoolean(false);18 private final AtomicReference<String> stringRef = new AtomicReference<>("initial");19 private final AtomicStampedReference<String> stampedRef = new AtomicStampedReference<>("A", 0);20 private final AtomicMarkableReference<String> markableRef = new AtomicMarkableReference<>("data", false);21 private final AtomicIntegerArray intArray = new AtomicIntegerArray(5);22 private final AtomicLongArray longArray = new AtomicLongArray(5);23 private final AtomicReferenceArray<String> refArray = new AtomicReferenceArray<>(5);24 private final AtomicIntegerFieldUpdater<AtomicClassOptimization> intUpdater =25 AtomicIntegerFieldUpdater.newUpdater(AtomicClassOptimization.class, "counter");26 private final AtomicLongFieldUpdater<AtomicClassOptimization> longUpdater =27 AtomicLongFieldUpdater.newUpdater(AtomicClassOptimization.class, "longCounter");28 private final AtomicReferenceFieldUpdater<AtomicClassOptimization, String> refUpdater =29 AtomicReferenceFieldUpdater.newUpdater(AtomicClassOptimization.class, String.class, "stringRef");30 31 /**32 * 减少CAS失败33 */34 public void optimizedIncrement() {35 while (true) {36 int current = counter.get();37 int next = current + 1;38 if (counter.compareAndSet(current, next)) {39 break;40 }41 // 可以添加退避策略42 Thread.yield();43 }44 }45 46 /**47 * 避免过度使用48 */49 public static class AvoidOveruse {50 // 不推荐:过度使用原子类51 private final AtomicInteger x = new AtomicInteger(0);52 private final AtomicInteger y = new AtomicInteger(0);53 private final AtomicInteger z = new AtomicInteger(0);54 55 // 推荐:使用复合对象56 public static class Point {57 private volatile int x, y, z;58 59 public synchronized void setCoordinates(int x, int y, int z) {60 this.x = x;61 this.y = y;62 this.z = z;63 }64 65 public synchronized int[] getCoordinates() {66 return new int[]{x, y, z};67 }68 }69 }70}7. 总结
原子类是Java并发编程中的重要工具,它们提供了高性能、无阻塞的线程安全操作。
7.1 关键要点
- CAS机制:比较并交换,无锁算法的基础
- 原子类分类:基本类型、引用类型、数组类型、字段更新器
- ABA问题:通过版本号或标记解决
- 性能优化:减少CAS失败、避免过度使用
7.2 选择建议
| 场景 | 推荐原子类 | 原因 |
|---|---|---|
| 简单计数器 | AtomicInteger/AtomicLong | 性能高,使用简单 |
| 对象引用 | AtomicReference | 支持泛型,功能丰富 |
| 需要版本控制 | AtomicStampedReference | 解决ABA问题 |
| 需要标记 | AtomicMarkableReference | 支持布尔标记 |
| 数组操作 | AtomicIntegerArray等 | 原子数组操作 |
| 字段更新 | 字段更新器 | 无需修改类结构 |
7.3 学习建议
- 理解原理:深入理解CAS机制的工作原理
- 实践验证:通过编写代码验证不同原子类的效果
- 性能测试:对比原子类与同步机制的性能差异
- 场景选择:根据具体需求选择合适的原子类
通过深入理解和熟练运用这些原子类技术,我们能够构建出更加高效、健壮和可维护的Java并发应用程序。
参与讨论