news 2026/4/23 12:51:46

Java并发编程利器:深入解析13个原子操作类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java并发编程利器:深入解析13个原子操作类

一、为什么需要原子操作类?

1.1 问题的由来

想象一下这样的场景:多个线程同时操作同一个银行账户进行取款,如果不加控制,可能会出现什么情况?

// 不安全的计数器示例

class UnsafeCounter {

private int count = 0;

public void increment() {

count++; // 这不是原子操作!

}

}

count++看似简单,实际上包含三个步骤:

读取count的当前值

将值加1

将新值写回count

在多线程环境下,这两个步骤可能被其他线程打断,导致数据不一致。

1.2 传统的解决方案及其缺点

传统做法是使用synchronized关键字:

class SynchronizedCounter {

private int count = 0;

public synchronized void increment() {

count++;

}

}

synchronized确实能保证线程安全,但存在以下问题:

性能开销:锁的获取和释放需要代价

可能死锁:不正确的锁顺序可能导致死锁

降低并发性:同一时刻只有一个线程能访问

1.3 原子操作类的优势

原子操作类基于CAS(Compare-And-Swap) 机制,提供了:

无锁编程:避免传统锁的开销

高性能:在低竞争环境下性能优异

无死锁风险:基于硬件指令,不会产生死锁

高并发:支持多个线程同时操作

二、原子更新基本类型类

2.1 AtomicBoolean - 原子更新布尔类型

使用场景:状态标志位、开关控制、条件判断

核心API详解

方法 参数 返回值 说明

get() - boolean 获取当前值

set(boolean newValue) newValue: 新值 void 设置新值

getAndSet(boolean newValue) newValue: 新值 boolean 原子性地设置为新值并返回旧值

compareAndSet(boolean expect, boolean update) expect: 期望值

update: 更新值 boolean 如果当前值等于期望值,则原子性地更新

lazySet(boolean newValue) newValue: 新值 void 最终设置为新值,但不保证立即可见性

weakCompareAndSet(boolean expect, boolean update) expect: 期望值

update: 更新值 boolean 可能更弱的CAS操作,在某些平台上性能更好

import java.util.concurrent.atomic.AtomicBoolean;

/**

* AtomicBoolean示例:用于原子性地更新布尔值

* 典型场景:系统开关、状态标志等

*/

public class AtomicBooleanDemo {

public static void main(String[] args) {

// 创建AtomicBoolean,初始值为false

AtomicBoolean atomicBoolean = new AtomicBoolean(false);

// get(): 获取当前值

System.out.println("初始值: " + atomicBoolean.get());

// getAndSet(): 原子性地设置为true,返回旧值

boolean oldValue = atomicBoolean.getAndSet(true);

System.out.println("getAndSet旧值: " + oldValue + ", 新值: " + atomicBoolean.get());

// compareAndSet(): 比较并设置

boolean success = atomicBoolean.compareAndSet(true, false);

System.out.println("CAS操作结果: " + success + ", 当前值: " + atomicBoolean.get());

// lazySet(): 最终会设置,但不保证立即可见性

atomicBoolean.lazySet(true);

System.out.println("lazySet后的值: " + atomicBoolean.get());

// weakCompareAndSet(): 弱版本CAS

boolean weakSuccess = atomicBoolean.weakCompareAndSet(true, false);

System.out.println("弱CAS操作结果: " + weakSuccess + ", 当前值: " + atomicBoolean.get());

}

}

原理分析:

AtomicBoolean内部实际上使用int类型来存储,0表示false,1表示true。通过compareAndSwapInt来实现原子操作。

2.2 AtomicInteger - 原子更新整型

使用场景:计数器、序列号生成、资源数量控制

核心API详解

方法 参数 返回值 说明

get() - int 获取当前值

set(int newValue) newValue: 新值 void 设置新值

getAndSet(int newValue) newValue: 新值 int 原子性地设置为新值并返回旧值

compareAndSet(int expect, int update) expect: 期望值

update: 更新值 boolean CAS操作

getAndIncrement() - int 原子递增,返回旧值

getAndDecrement() - int 原子递减,返回旧值

getAndAdd(int delta) delta: 增量 int 原子加法,返回旧值

incrementAndGet() - int 原子递增,返回新值

decrementAndGet() - int 原子递减,返回新值

addAndGet(int delta) delta: 增量 int 原子加法,返回新值

updateAndGet(IntUnaryOperator) operator: 更新函数 int 函数式更新

accumulateAndGet(int x, IntBinaryOperator) x: 参数

operator: 操作函数 int 累积计算

import java.util.concurrent.atomic.AtomicInteger;

/**

* AtomicInteger是最常用的原子类之一

* 适用于计数器、ID生成器等需要原子递增的场景

*/

public class AtomicIntegerDemo {

public static void main(String[] args) {

AtomicInteger atomicInt = new AtomicInteger(0);

// 基础操作

System.out.println("初始值: " + atomicInt.get());

atomicInt.set(5);

System.out.println("set(5)后: " + atomicInt.get());

// 原子递增并返回旧值 - 常用于计数

System.out.println("getAndIncrement: " + atomicInt.getAndIncrement()); // 返回5

System.out.println("当前值: " + atomicInt.get()); // 6

// 原子递减并返回旧值

System.out.println("getAndDecrement: " + atomicInt.getAndDecrement()); // 返回6

System.out.println("当前值: " + atomicInt.get()); // 5

// 原子加法并返回旧值

System.out.println("getAndAdd(10): " + atomicInt.getAndAdd(10)); // 返回5

System.out.println("当前值: " + atomicInt.get()); // 15

// 原子递增并返回新值

System.out.println("incrementAndGet: " + atomicInt.incrementAndGet()); // 16

// 原子加法并返回结果 - 适合批量增加

int result = atomicInt.addAndGet(10);

System.out.println("addAndGet(10)结果: " + result); // 26

// 比较并设置 - 核心CAS操作

boolean updated = atomicInt.compareAndSet(26, 30);

System.out.println("CAS操作结果: " + updated + ", 当前值: " + atomicInt.get());

// 获取并设置新值 - 适合重置操作

int previous = atomicInt.getAndSet(40);

System.out.println("getAndSet旧值: " + previous + ", 新值: " + atomicInt.get());

// JDK8新增:函数式更新 - 更灵活的更新方式

atomicInt.updateAndGet(x -> x * 2);

System.out.println("updateAndGet(*2)后的值: " + atomicInt.get()); // 80

// 累积计算

atomicInt.accumulateAndGet(10, (x, y) -> x + y * 2);

System.out.println("accumulateAndGet后的值: " + atomicInt.get()); // 100

}

}

源码分析:

public final int getAndIncrement() {

// 自旋CAS:循环直到成功

for (;;) {

int current = get(); // 步骤1:获取当前值

int next = current + 1; // 步骤2:计算新值

if (compareAndSet(current, next)) // 步骤3:CAS更新

return current; // 成功则返回旧值

}

// 如果CAS失败,说明有其他线程修改了值,循环重试

}

2.3 AtomicLong - 原子更新长整型

使用场景:大数值计数器、统计信息、唯一ID生成

核心API详解

方法 参数 返回值 说明

get() - long 获取当前值

set(long newValue) newValue: 新值 void 设置新值

getAndSet(long newValue) newValue: 新值 long 原子性地设置为新值并返回旧值

compareAndSet(long expect, long update) expect: 期望值

update: 更新值 boolean CAS操作

getAndIncrement() - long 原子递增,返回旧值

getAndDecrement() - long 原子递减,返回旧值

getAndAdd(long delta) delta: 增量 long 原子加法,返回旧值

incrementAndGet() - long 原子递增,返回新值

decrementAndGet() - long 原子递减,返回新值

addAndGet(long delta) delta: 增量 long 原子加法,返回新值

updateAndGet(LongUnaryOperator) operator: 更新函数 long 函数式更新

accumulateAndGet(long x, LongBinaryOperator) x: 参数

operator: 操作函数 long 累积计算

import java.util.concurrent.atomic.AtomicLong;

/**

* AtomicLong用于长整型的原子操作

* 在64位系统中性能与AtomicInteger相当

*/

public class AtomicLongDemo {

public static void main(String[] args) {

AtomicLong atomicLong = new AtomicLong(100L);

System.out.println("初始值: " + atomicLong.get());

// 原子递增并返回旧值 - 适合序列号生成

System.out.println("getAndIncrement: " + atomicLong.getAndIncrement());

System.out.println("当前值: " + atomicLong.get());

// 原子递减并返回旧值

System.out.println("getAndDecrement: " + atomicLong.getAndDecrement());

System.out.println("当前值: " + atomicLong.get());

// 原子加法并返回旧值

System.out.println("getAndAdd(50): " + atomicLong.getAndAdd(50L));

System.out.println("当前值: " + atomicLong.get());

// 原子递增并返回新值

System.out.println("incrementAndGet: " + atomicLong.incrementAndGet());

// 原子加法并返回结果 - 适合统计累加

long newValue = atomicLong.addAndGet(50L);

System.out.println("addAndGet(50)结果: " + newValue);

// 比较并设置

boolean success = atomicLong.compareAndSet(250L, 300L);

System.out.println("CAS操作结果: " + success + ", 当前值: " + atomicLong.get());

// JDK8新增:函数式更新

atomicLong.updateAndGet(x -> x / 2);

System.out.println("updateAndGet(/2)后的值: " + atomicLong.get());

// JDK8新增:累积计算 - 适合复杂的原子计算

atomicLong.accumulateAndGet(100L, (x, y) -> x * y);

System.out.println("accumulateAndGet后的值: " + atomicLong.get());

}

}

性能提示:

在32位系统上,AtomicLong的CAS操作可能需要锁住总线,性能相对较差。Java 8提供了LongAdder作为高性能替代方案。

三、原子更新数组类

3.1 AtomicIntegerArray - 原子更新整型数组

使用场景:并发计数器数组、桶统计、并行计算

核心API详解

方法 参数 返回值 说明

length() - int 返回数组长度

get(int i) i: 索引 int 获取指定索引的值

set(int i, int newValue) i: 索引

newValue: 新值 void 设置指定索引的值

getAndSet(int i, int newValue) i: 索引

newValue: 新值 int 原子设置并返回旧值

compareAndSet(int i, int expect, int update) i: 索引

expect: 期望值

update: 更新值 boolean 对指定索引进行CAS操作

getAndIncrement(int i) i: 索引 int 原子递增指定索引,返回旧值

getAndDecrement(int i) i: 索引 int 原子递减指定索引,返回旧值

getAndAdd(int i, int delta) i: 索引

delta: 增量 int 原子加法,返回旧值

incrementAndGet(int i) i: 索引 int 原子递增指定索引,返回新值

addAndGet(int i, int delta) i: 索引

delta: 增量 int 原子加法,返回新值

import java.util.concurrent.atomic.AtomicIntegerArray;

/**

* AtomicIntegerArray允许原子地更新数组中的单个元素

* 注意:构造函数会复制传入的数组,不影响原数组

*/

public class AtomicIntegerArrayDemo {

public static void main(String[] args) {

int[] initialArray = {1, 2, 3, 4, 5};

// 创建原子整型数组,会复制传入的数组

AtomicIntegerArray atomicArray = new AtomicIntegerArray(initialArray);

System.out.println("数组长度: " + atomicArray.length());

System.out.println("原始数组: " + atomicArray.toString());

// get(): 获取指定索引的值

System.out.println("索引0的值: " + atomicArray.get(0));

// set(): 设置指定索引的值

atomicArray.set(0, 10);

System.out.println("set(0, 10)后的数组: " + atomicArray.toString());

// getAndSet(): 原子更新指定索引的元素并返回旧值

int oldValue = atomicArray.getAndSet(1, 20);

System.out.println("索引1替换前的值: " + oldValue + ", 数组: " + atomicArray.toString());

// getAndIncrement(): 原子递增指定索引的元素 - 适合分桶计数

oldValue = atomicArray.getAndIncrement(2);

System.out.println("索引2递增前值: " + oldValue + ", 数组: " + atomicArray.toString());

// compareAndSet(): 比较并设置特定位置的元素

boolean updated = atomicArray.compareAndSet(3, 4, 40);

System.out.println("索引3 CAS结果: " + updated + ", 数组: " + atomicArray.toString());

// addAndGet(): 原子加法 - 适合累加统计

int newValue = atomicArray.addAndGet(4, 5);

System.out.println("索引4加5后的值: " + newValue + ", 数组: " + atomicArray.toString());

// incrementAndGet(): 原子递增并返回新值

newValue = atomicArray.incrementAndGet(0);

System.out.println("索引0递增后的值: " + newValue);

// 重要:原始数组不会被修改

System.out.println("原始数组值未被修改: " + initialArray[0]); // 仍然是1

}

}

设计思想:

AtomicIntegerArray通过复制数组来避免外部修改,每个数组元素的更新都是独立的原子操作。

3.2 AtomicLongArray - 原子更新长整型数组

使用场景:大数据统计、时间戳数组、大数值桶统计

核心API详解

方法 参数 返回值 说明

length() - int 返回数组长度

get(int i) i: 索引 long 获取指定索引的值

set(int i, long newValue) i: 索引

newValue: 新值 void 设置指定索引的值

getAndSet(int i, long newValue) i: 索引

newValue: 新值 long 原子设置并返回旧值

compareAndSet(int i, long expect, long update) i: 索引

expect: 期望值

update: 更新值 boolean 对指定索引进行CAS操作

getAndAdd(int i, long delta) i: 索引

delta: 增量 long 原子加法,返回旧值

addAndGet(int i, long delta) i: 索引

delta: 增量 long 原子加法,返回新值

import java.util.concurrent.atomic.AtomicLongArray;

/**

* AtomicLongArray提供长整型数组的原子操作

* 适用于需要大数值范围的并发统计

*/

public class AtomicLongArrayDemo {

public static void main(String[] args) {

long[] initialArray = {100L, 200L, 300L, 400L, 500L};

AtomicLongArray atomicLongArray = new AtomicLongArray(initialArray);

System.out.println("数组长度: " + atomicLongArray.length());

System.out.println("初始数组: " + atomicLongArray.toString());

// 基础操作

System.out.println("索引0的值: " + atomicLongArray.get(0));

atomicLongArray.set(0, 150L);

System.out.println("set(0, 150)后的数组: " + atomicLongArray.toString());

// 原子更新操作

long oldValue = atomicLongArray.getAndSet(1, 250L);

System.out.println("索引1替换前的值: " + oldValue + ", 数组: " + atomicLongArray.toString());

// 原子加法操作

atomicLongArray.getAndAdd(2, 100L);

System.out.println("索引2加100后的数组: " + atomicLongArray.toString());

// 比较并设置

atomicLongArray.compareAndSet(3, 400L, 450L);

System.out.println("索引3 CAS后的数组: " + atomicLongArray.toString());

// 加法并获取新值

long newValue = atomicLongArray.addAndGet(4, 200L);

System.out.println("索引4加200后的值: " + newValue);

}

}

3.3 AtomicReferenceArray - 原子更新引用类型数组

使用场景:对象池、缓存数组、并发数据结构

核心API详解

方法 参数 返回值 说明

length() - int 返回数组长度

get(int i) i: 索引 E 获取指定索引的引用

set(int i, E newValue) i: 索引

newValue: 新引用 void 设置指定索引的引用

getAndSet(int i, E newValue) i: 索引

newValue: 新引用 E 原子设置并返回旧引用

compareAndSet(int i, E expect, E update) i: 索引

expect: 期望引用

update: 更新引用 boolean 对指定索引进行CAS操作

lazySet(int i, E newValue) i: 索引

newValue: 新引用 void 延迟设置引用

import java.util.concurrent.atomic.AtomicReferenceArray;

/**

* AtomicReferenceArray用于原子更新引用类型数组

* 适用于对象引用需要原子更新的场景

*/

public class AtomicReferenceArrayDemo {

static class Person {

String name;

int age;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

@Override

public String toString() {

return name + "(" + age + ")";

}

}

public static void main(String[] args) {

Person[] persons = {

new Person("Alice", 25),

new Person("Bob", 30),

new Person("Charlie", 35),

new Person("David", 40)

};

AtomicReferenceArray<Person> atomicArray = new AtomicReferenceArray<>(persons);

System.out.println("数组长度: " + atomicArray.length());

System.out.println("初始数组: ");

for (int i = 0; i < atomicArray.length(); i++) {

System.out.println("索引 " + i + ": " + atomicArray.get(i));

}

// 原子更新引用 - 适合对象替换

Person newPerson = new Person("Eve", 28);

Person oldPerson = atomicArray.getAndSet(1, newPerson);

System.out.println("索引1替换: " + oldPerson + " -> " + atomicArray.get(1));

// 比较并设置引用

boolean success = atomicArray.compareAndSet(2, persons[2], new Person("Frank", 45));

System.out.println("索引2 CAS结果: " + success + ", 新值: " + atomicArray.get(2));

// 延迟设置

atomicArray.lazySet(3, new Person("Grace", 50));

System.out.println("索引3延迟设置后的值: " + atomicArray.get(3));

// 遍历数组

System.out.println("最终数组状态:");

for (int i = 0; i < atomicArray.length(); i++) {

System.out.println("索引 " + i + ": " + atomicArray.get(i));

}

}

}

四、原子更新引用类型

4.1 AtomicReference - 原子更新引用类型

使用场景:单例模式、缓存更新、状态对象替换

核心API详解

方法 参数 返回值 说明

get() - V 获取当前引用

set(V newValue) newValue: 新引用 void 设置新引用

getAndSet(V newValue) newValue: 新引用 V 原子设置并返回旧引用

compareAndSet(V expect, V update) expect: 期望引用

update: 更新引用 boolean CAS操作

weakCompareAndSet(V expect, V update) expect: 期望引用

update: 更新引用 boolean 弱版本CAS

lazySet(V newValue) newValue: 新引用 void 延迟设置引用

updateAndGet(UnaryOperator<V>) operator: 更新函数 V 函数式更新

getAndUpdate(UnaryOperator<V>) operator: 更新函数 V 函数式更新并返回旧值

accumulateAndGet(V x, BinaryOperator<V>) x: 参数

operator: 操作函数 V 累积计算

import java.util.concurrent.atomic.AtomicReference;

/**

* AtomicReference用于原子更新对象引用

* 解决"先检查后执行"的竞态条件

*/

public class AtomicReferenceDemo {

static class User {

private String name;

private int age;

public User(String name, int age) {

this.name = name;

this.age = age;

}

public String getName() { return name; }

public int getAge() { return age; }

@Override

public String toString() {

return "User{name='" + name + "', age=" + age + "}";

}

}

public static void main(String[] args) {

AtomicReference<User> atomicUser = new AtomicReference<>();

User initialUser = new User("张三", 25);

atomicUser.set(initialUser);

System.out.println("初始用户: " + atomicUser.get());

// getAndSet(): 原子更新引用 - 适合缓存更新

User newUser = new User("李四", 30);

User oldUser = atomicUser.getAndSet(newUser);

System.out.println("替换前的用户: " + oldUser);

System.out.println("当前用户: " + atomicUser.get());

// compareAndSet(): 比较并设置 - 核心操作

boolean success = atomicUser.compareAndSet(newUser, new User("王五", 35));

System.out.println("CAS操作结果: " + success + ", 当前用户: " + atomicUser.get());

// weakCompareAndSet(): 弱版本CAS

boolean weakSuccess = atomicUser.weakCompareAndSet(

atomicUser.get(), new User("赵六", 40));

System.out.println("弱CAS操作结果: " + weakSuccess + ", 当前用户: " + atomicUser.get());

// lazySet(): 延迟设置

atomicUser.lazySet(new User("孙七", 45));

System.out.println("延迟设置后的用户: " + atomicUser.get());

// JDK8新增:函数式更新

atomicUser.updateAndGet(user -> new User(user.getName() + "_updated", user.getAge() + 1));

System.out.println("函数式更新后的用户: " + atomicUser.get());

// getAndUpdate(): 函数式更新并返回旧值

User previous = atomicUser.getAndUpdate(user -> new User("周八", 50));

System.out.println("更新前的用户: " + previous + ", 当前用户: " + atomicUser.get());

// accumulateAndGet(): 累积计算

atomicUser.accumulateAndGet(new User("吴九", 55),

(old, param) -> new User(old.getName() + "&" + param.getName(),

old.getAge() + param.getAge()));

System.out.println("累积计算后的用户: " + atomicUser.get());

}

}

典型应用:单例模式的双重检查锁定

class Singleton {

private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();

public static Singleton getInstance() {

for (;;) {

Singleton current = INSTANCE.get();

if (current != null) return current;

current = new Singleton();

if (INSTANCE.compareAndSet(null, current)) {

return current;

}

}

}

}

4.2 AtomicMarkableReference - 带标记位的原子引用

使用场景:带状态的缓存、ABA问题简单解决方案

核心API详解

方法 参数 返回值 说明

getReference() - V 获取当前引用

isMarked() - boolean 获取当前标记位

get(boolean[] markHolder) markHolder: 标记位容器 V 获取引用和标记位

set(V newReference, boolean newMark) newReference: 新引用

newMark: 新标记 void 设置引用和标记位

compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) expectedReference: 期望引用

newReference: 新引用

expectedMark: 期望标记

newMark: 新标记 boolean 同时比较引用和标记位

attemptMark(V expectedReference, boolean newMark) expectedReference: 期望引用

newMark: 新标记 boolean 尝试只更新标记位

import java.util.concurrent.atomic.AtomicMarkableReference;

/**

* AtomicMarkableReference将引用与一个布尔标记位绑定

* 适用于需要同时更新引用和状态的场景

*/

public class AtomicMarkableReferenceDemo {

public static void main(String[] args) {

String initialRef = "初始数据";

boolean initialMark = false;

// 创建带标记位的原子引用

AtomicMarkableReference<String> atomicMarkableRef =

new AtomicMarkableReference<>(initialRef, initialMark);

System.out.println("初始引用: " + atomicMarkableRef.getReference());

System.out.println("初始标记: " + atomicMarkableRef.isMarked());

// get(boolean[]): 同时获取引用和标记位

boolean[] markHolder = new boolean[1];

String currentRef = atomicMarkableRef.get(markHolder);

System.out.println("当前引用: " + currentRef + ", 当前标记: " + markHolder[0]);

// compareAndSet(): 尝试同时更新引用和标记位

String newRef = "新数据";

boolean newMark = true;

boolean success = atomicMarkableRef.compareAndSet(

initialRef, newRef, initialMark, newMark);

System.out.println("CAS操作结果: " + success);

System.out.println("新引用: " + atomicMarkableRef.getReference());

System.out.println("新标记: " + atomicMarkableRef.isMarked());

// attemptMark(): 只尝试更新标记位

boolean markUpdated = atomicMarkableRef.attemptMark(newRef, false);

System.out.println("标记更新结果: " + markUpdated);

System.out.println("最终标记: " + atomicMarkableRef.isMarked());

// set(): 直接设置引用和标记位

atomicMarkableRef.set("最终数据", true);

System.out.println("直接设置后的引用: " + atomicMarkableRef.getReference());

System.out.println("直接设置后的标记: " + atomicMarkableRef.isMarked());

}

}

4.3 AtomicStampedReference - 带版本号的原子引用

使用场景:解决ABA问题、乐观锁实现

核心API详解

方法 参数 返回值 说明

getReference() - V 获取当前引用

getStamp() - int 获取当前版本号

get(int[] stampHolder) stampHolder: 版本号容器 V 获取引用和版本号

set(V newReference, int newStamp) newReference: 新引用

newStamp: 新版本号 void 设置引用和版本号

compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) expectedReference: 期望引用

newReference: 新引用

expectedStamp: 期望版本号

newStamp: 新版本号 boolean 同时比较引用和版本号

attemptStamp(V expectedReference, int newStamp) expectedReference: 期望引用

newStamp: 新版本号 boolean 尝试只更新版本号

import java.util.concurrent.atomic.AtomicStampedReference;

/**

* AtomicStampedReference通过版本号解决ABA问题

* 每次修改都会增加版本号,确保不会误判

*/

public class AtomicStampedReferenceDemo {

public static void main(String[] args) {

String initialRef = "数据A";

int initialStamp = 0;

// 创建带版本号的原子引用

AtomicStampedReference<String> atomicStampedRef =

new AtomicStampedReference<>(initialRef, initialStamp);

System.out.println("初始引用: " + atomicStampedRef.getReference());

System.out.println("初始版本号: " + atomicStampedRef.getStamp());

// get(int[]): 同时获取引用和版本号

int[] stampHolder = new int[1];

String currentRef = atomicStampedRef.get(stampHolder);

System.out.println("当前引用: " + currentRef + ", 当前版本号: " + stampHolder[0]);

// 模拟ABA问题场景

String newRefB = "数据B";

String newRefA = "数据A"; // 又改回A,但版本号不同

// 第一次更新:A -> B,版本号 0 -> 1

boolean firstUpdate = atomicStampedRef.compareAndSet(

initialRef, newRefB, initialStamp, initialStamp + 1);

System.out.println("第一次更新(A->B)结果: " + firstUpdate);

System.out.println("当前引用: " + atomicStampedRef.getReference());

System.out.println("当前版本号: " + atomicStampedRef.getStamp());

// 第二次更新:B -> A,版本号 1 -> 2

boolean secondUpdate = atomicStampedRef.compareAndSet(

newRefB, newRefA, 1, 2);

System.out.println("第二次更新(B->A)结果: " + secondUpdate);

System.out.println("当前引用: " + atomicStampedRef.getReference());

System.out.println("当前版本号: " + atomicStampedRef.getStamp());

// 尝试用旧版本号更新(会失败)- 这就是解决ABA问题的关键!

boolean failedUpdate = atomicStampedRef.compareAndSet(

newRefA, "新数据", 0, 1); // 使用旧的版本号0

System.out.println("使用旧版本号更新结果: " + failedUpdate);

System.out.println("引用未被修改: " + atomicStampedRef.getReference());

// attemptStamp(): 只更新版本号

boolean stampUpdated = atomicStampedRef.attemptStamp(newRefA, 3);

System.out.println("版本号更新结果: " + stampUpdated);

System.out.println("新版本号: " + atomicStampedRef.getStamp());

// 正确的方式:使用当前版本号

stampHolder = new int[1];

currentRef = atomicStampedRef.get(stampHolder);

boolean correctUpdate = atomicStampedRef.compareAndSet(

currentRef, "最终数据", stampHolder[0], stampHolder[0] + 1);

System.out.println("使用正确版本号更新结果: " + correctUpdate);

System.out.println("最终引用: " + atomicStampedRef.getReference());

System.out.println("最终版本号: " + atomicStampedRef.getStamp());

}

}

ABA问题详解:

ABA问题是指:

线程1读取值A

线程2将值改为B,然后又改回A

线程1进行CAS操作,发现当前值仍是A,于是操作成功

虽然值看起来没变,但中间状态的变化可能对业务逻辑产生影响。AtomicStampedReference通过版本号完美解决了这个问题。

五、原子更新字段类

5.1 AtomicIntegerFieldUpdater - 原子更新整型字段

使用场景:优化内存使用、大量对象需要原子字段更新

核心API详解

方法 参数 返回值 说明

newUpdater(Class<U> tclass, String fieldName) tclass: 目标类

fieldName: 字段名 AtomicIntegerFieldUpdater<U> 静态方法创建更新器

get(U obj) obj: 目标对象 int 获取字段值

set(U obj, int newValue) obj: 目标对象

newValue: 新值 void 设置字段值

getAndSet(U obj, int newValue) obj: 目标对象

newValue: 新值 int 原子设置并返回旧值

compareAndSet(U obj, int expect, int update) obj: 目标对象

expect: 期望值

update: 更新值 boolean CAS操作

getAndIncrement(U obj) obj: 目标对象 int 原子递增,返回旧值

getAndDecrement(U obj) obj: 目标对象 int 原子递减,返回旧值

getAndAdd(U obj, int delta) obj: 目标对象

delta: 增量 int 原子加法,返回旧值

incrementAndGet(U obj) obj: 目标对象 int 原子递增,返回新值

addAndGet(U obj, int delta) obj: 目标对象

delta: 增量 int 原子加法,返回新值

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**

* AtomicIntegerFieldUpdater以原子方式更新对象的volatile int字段

* 相比为每个对象创建AtomicInteger,可以节省大量内存

*/

public class AtomicIntegerFieldUpdaterDemo {

static class Counter {

// 必须用volatile修饰,保证可见性

public volatile int count;

private String name;

public Counter(String name, int initialCount) {

this.name = name;

this.count = initialCount;

}

public String getName() { return name; }

public int getCount() { return count; }

}

public static void main(String[] args) {

// 创建字段更新器,指定要更新的类和字段名

AtomicIntegerFieldUpdater<Counter> updater =

AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");

Counter counter1 = new Counter("计数器1", 0);

Counter counter2 = new Counter("计数器2", 10);

System.out.println("计数器1初始计数: " + counter1.getCount());

System.out.println("计数器2初始计数: " + counter2.getCount());

// get(): 获取字段值

System.out.println("通过updater获取计数器1的值: " + updater.get(counter1));

// set(): 设置字段值

updater.set(counter1, 5);

System.out.println("设置计数器1为5后的值: " + counter1.getCount());

// getAndIncrement(): 原子递增 - 相比synchronized性能更好

int oldCount = updater.getAndIncrement(counter1);

System.out.println("计数器1递增前值: " + oldCount + ", 当前值: " + counter1.getCount());

// getAndAdd(): 原子加法

oldCount = updater.getAndAdd(counter1, 10);

System.out.println("计数器1加10前值: " + oldCount + ", 当前值: " + counter1.getCount());

// incrementAndGet(): 原子递增并返回新值

int newCount = updater.incrementAndGet(counter1);

System.out.println("计数器1递增后的值: " + newCount);

// addAndGet(): 原子加法并返回新值

newCount = updater.addAndGet(counter1, 20);

System.out.println("计数器1加20后的值: " + newCount);

// compareAndSet(): 比较并设置

boolean updated = updater.compareAndSet(counter1, 36, 50);

System.out.println("计数器1 CAS操作结果: " + updated + ", 当前值: " + counter1.getCount());

// 可以同时更新多个对象的相同字段

updater.incrementAndGet(counter2);

System.out.println("计数器2递增后的值: " + counter2.getCount());

}

}

内存优化效果:

AtomicInteger对象:16-24字节 overhead

volatile int + AtomicIntegerFieldUpdater:4字节 + 静态updater

当有大量对象时,内存节省效果显著

5.2 AtomicLongFieldUpdater - 原子更新长整型字段

使用场景:大数值字段的原子更新、内存敏感场景

核心API详解

方法 参数 返回值 说明

newUpdater(Class<U> tclass, String fieldName) tclass: 目标类

fieldName: 字段名 AtomicLongFieldUpdater<U> 静态方法创建更新器

get(U obj) obj: 目标对象 long 获取字段值

set(U obj, long newValue) obj: 目标对象

newValue: 新值 void 设置字段值

getAndSet(U obj, long newValue) obj: 目标对象

newValue: 新值 long 原子设置并返回旧值

compareAndSet(U obj, long expect, long update) obj: 目标对象

expect: 期望值

update: 更新值 boolean CAS操作

getAndAdd(U obj, long delta) obj: 目标对象

delta: 增量 long 原子加法,返回旧值

addAndGet(U obj, long delta) obj: 目标对象

delta: 增量 long 原子加法,返回新值

import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**

* AtomicLongFieldUpdater用于原子更新long字段

* 适用于需要大数值范围且内存敏感的场景

*/

public class AtomicLongFieldUpdaterDemo {

static class Account {

// 必须用volatile修饰

public volatile long balance;

private final String owner;

public Account(String owner, long initialBalance) {

this.owner = owner;

this.balance = initialBalance;

}

public String getOwner() { return owner; }

public long getBalance() { return balance; }

}

public static void main(String[] args) {

AtomicLongFieldUpdater<Account> balanceUpdater =

AtomicLongFieldUpdater.newUpdater(Account.class, "balance");

Account account1 = new Account("张三", 1000L);

Account account2 = new Account("李四", 2000L);

System.out.println("张三账户初始余额: " + account1.getBalance());

System.out.println("李四账户初始余额: " + account2.getBalance());

// 基础操作

System.out.println("通过updater获取张三余额: " + balanceUpdater.get(account1));

balanceUpdater.set(account1, 1500L);

System.out.println("设置张三余额为1500后的值: " + account1.getBalance());

// 原子存款 - 无锁线程安全

balanceUpdater.addAndGet(account1, 500L);

System.out.println("张三存款500后余额: " + account1.getBalance());

// 原子取款

long oldBalance = balanceUpdater.getAndAdd(account1, -200L);

System.out.println("张三取款200前余额: " + oldBalance + ", 取款后余额: " + account1.getBalance());

// 比较并设置 - 实现转账等业务

boolean transferSuccess = balanceUpdater.compareAndSet(account1, 1800L, 2000L);

System.out.println("张三转账操作结果: " + transferSuccess + ", 当前余额: " + account1.getBalance());

// 同时操作多个账户

balanceUpdater.getAndAdd(account2, 1000L);

System.out.println("李四存款1000后余额: " + account2.getBalance());

}

}

5.3 AtomicReferenceFieldUpdater - 原子更新引用字段

使用场景:链表节点更新、树结构调整、对象关系维护

核心API详解

方法 参数 返回值 说明

newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) tclass: 目标类

vclass: 字段类型

fieldName: 字段名 AtomicReferenceFieldUpdater<U,W> 静态方法创建更新器

get(U obj) obj: 目标对象 V 获取字段引用

set(U obj, V newValue) obj: 目标对象

newValue: 新引用 void 设置字段引用

getAndSet(U obj, V newValue) obj: 目标对象

newValue: 新引用 V 原子设置并返回旧引用

compareAndSet(U obj, V expect, V update) obj: 目标对象

expect: 期望引用

update: 更新引用 boolean CAS操作

lazySet(U obj, V newValue) obj: 目标对象

newValue: 新引用 void 延迟设置引用

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**

* AtomicReferenceFieldUpdater用于原子更新引用字段

* 常用于实现无锁数据结构

*/

public class AtomicReferenceFieldUpdaterDemo {

static class Node<T> {

// 必须用volatile修饰

public volatile Node<T> next;

private final T value;

public Node(T value) {

this.value = value;

}

public T getValue() { return value; }

public Node<T> getNext() { return next; }

@Override

public String toString() {

return "Node{value=" + value + ", next=" + (next != null ? next.value : "null") + "}";

}

}

public static void main(String[] args) {

// 创建引用字段更新器

AtomicReferenceFieldUpdater<Node, Node> nextUpdater =

AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "next");

Node<String> first = new Node<>("第一个节点");

Node<String> second = new Node<>("第二个节点");

Node<String> third = new Node<>("第三个节点");

System.out.println("初始第一个节点的next: " + first.getNext());

// get(): 获取字段引用

System.out.println("通过updater获取第一个节点的next: " + nextUpdater.get(first));

// set(): 设置字段引用

nextUpdater.set(first, second);

System.out.println("设置第一个节点的next为第二个节点: " + first);

// compareAndSet(): 原子设置next字段 - 实现无锁链表

boolean setSuccess = nextUpdater.compareAndSet(first, second, third);

System.out.println("CAS操作结果: " + setSuccess);

System.out.println("第一个节点: " + first);

// getAndSet(): 获取并设置引用

Node<String> oldNext = nextUpdater.getAndSet(second, third);

System.out.println("第二个节点原来的next: " + oldNext);

System.out.println("第二个节点: " + second);

// lazySet(): 延迟设置

nextUpdater.lazySet(third, first); // 形成环状,仅作演示

System.out.println("第三个节点延迟设置后的next: " + third.getNext());

// 构建链表并展示

System.out.println("最终链表结构:");

Node<String> current = first;

int count = 0;

while (current != null && count < 5) { // 防止无限循环

System.out.println(current);

current = current.getNext();

count++;

}

}

}

六、综合实战:构建线程安全计数器

下面我们通过一个综合示例展示如何在实际项目中使用原子操作类:

import java.util.concurrent.atomic.*;

import java.util.concurrent.*;

/**

* 线程安全计数器综合示例

* 展示了多种原子类的实际应用

*/

public class ThreadSafeCounter {

// 基本计数器 - 使用AtomicInteger

private final AtomicInteger count = new AtomicInteger(0);

// 大数值统计 - 使用AtomicLong

private final AtomicLong total = new AtomicLong(0L);

// 状态控制 - 使用AtomicReference

private final AtomicReference<String> status = new AtomicReference<>("RUNNING");

// 统计数组 - 使用AtomicIntegerArray进行分桶统计

private final AtomicIntegerArray bucketStats = new AtomicIntegerArray(10);

// 配置信息 - 使用AtomicReference支持动态更新

private final AtomicReference<Config> config = new AtomicReference<>(new Config(100, 60));

// 标记位控制 - 使用AtomicBoolean

private final AtomicBoolean enabled = new AtomicBoolean(true);

static class Config {

final int maxConnections;

final int timeoutSeconds;

public Config(int maxConnections, int timeoutSeconds) {

this.maxConnections = maxConnections;

this.timeoutSeconds = timeoutSeconds;

}

@Override

public String toString() {

return "Config{maxConnections=" + maxConnections +

", timeoutSeconds=" + timeoutSeconds + "}";

}

}

// 核心API方法

public void increment() {

if (!enabled.get()) {

System.out.println("计数器已禁用,忽略操作");

return;

}

count.incrementAndGet();

total.addAndGet(1L);

// 分桶统计:根据count值决定放入哪个桶

int bucket = count.get() % 10;

bucketStats.getAndIncrement(bucket);

}

public void add(int value) {

if (!enabled.get()) {

System.out.println("计数器已禁用,忽略操作");

return;

}

count.addAndGet(value);

total.addAndGet(value);

}

public boolean setStatus(String expected, String newStatus) {

return status.compareAndSet(expected, newStatus);

}

public void updateConfig(Config newConfig) {

Config oldConfig;

do {

oldConfig = config.get();

System.out.println("尝试更新配置: " + oldConfig + " -> " + newConfig);

} while (!config.compareAndSet(oldConfig, newConfig));

System.out.println("配置更新成功");

}

public boolean enable() {

return enabled.compareAndSet(false, true);

}

public boolean disable() {

return enabled.compareAndSet(true, false);

}

// 获取统计信息

public void printStats() {

System.out.println("\n=== 统计信息 ===");

System.out.println("当前计数: " + count.get());

System.out.println("总数: " + total.get());

System.out.println("状态: " + status.get());

System.out.println("启用状态: " + enabled.get());

System.out.println("桶统计: " + bucketStats.toString());

Config currentConfig = config.get();

System.out.println("配置: " + currentConfig);

// 验证数据一致性

long sum = 0;

for (int i = 0; i < bucketStats.length(); i++) {

sum += bucketStats.get(i);

}

System.out.println("桶统计总和: " + sum + ", 计数: " + count.get() +

", 一致性: " + (sum == count.get()));

}

public static void main(String[] args) throws InterruptedException {

ThreadSafeCounter counter = new ThreadSafeCounter();

// 创建多个线程同时操作计数器

int threadCount = 10;

int operationsPerThread = 1000;

ExecutorService executor = Executors.newFixedThreadPool(threadCount);

CountDownLatch latch = new CountDownLatch(threadCount);

System.out.println("开始并发测试...");

for (int i = 0; i < threadCount; i++) {

final int threadId = i;

executor.execute(() -> {

try {

for (int j = 0; j < operationsPerThread; j++) {

counter.increment();

// 每隔一定操作数更新配置

if (j % 200 == 0) {

counter.updateConfig(new Config(100 + j, 60));

}

// 模拟随机禁用/启用

if (j == 500 && threadId == 0) {

System.out.println("线程" + threadId + "尝试禁用计数器");

counter.disable();

Thread.sleep(10); // 短暂休眠

System.out.println("线程" + threadId + "尝试启用计数器");

counter.enable();

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 18:18:18

Plex动漫插件终极指南:轻松打造完美动漫库

Plex动漫插件终极指南&#xff1a;轻松打造完美动漫库 【免费下载链接】Hama.bundle Plex HTTP Anidb Metadata Agent (HAMA) 项目地址: https://gitcode.com/gh_mirrors/ha/Hama.bundle 还在为Plex动漫库的混乱识别而烦恼吗&#xff1f;想要实现动漫元数据自动匹配和海…

作者头像 李华
网站建设 2026/4/23 12:11:21

【Java毕设全套源码+文档】基于Java的横向课题信息管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/23 14:00:33

MinIO替代方案生态集成指南:RustFS如何无缝融入现代技术栈

存储系统的价值从不是“单打独斗”&#xff0c;而是能否与现有技术生态无缝衔接——这也是MinIO迁移时最容易被忽略的关键&#xff1a;选对方案但集成不畅&#xff0c;照样会导致业务中断、运维成本飙升。 本文聚焦主推方案RustFS&#xff0c;从技术团队最关心的5大核心集成场景…

作者头像 李华
网站建设 2026/4/23 14:00:04

腾讯混元3D部件分割技术:从JavaScript到Python的完整迁移指南

腾讯混元3D部件分割技术&#xff1a;从JavaScript到Python的完整迁移指南 【免费下载链接】Hunyuan3D-Part 腾讯混元3D-Part 项目地址: https://ai.gitcode.com/tencent_hunyuan/Hunyuan3D-Part 还在为跨语言语法迁移而烦恼吗&#xff1f;今天我要分享一个超级实用的解决…

作者头像 李华
网站建设 2026/4/23 13:53:13

windows著名漏洞——内核提权漏洞

引言&#xff1a;隐匿在系统深处的“万能钥匙” 我们要探讨的是一个既专业又紧迫的议题——内核提权漏洞。在数字世界的底层&#xff0c;存在着一种特殊的“万能钥匙”&#xff0c;它能打开计算机系统最核心的保险库&#xff0c;让攻击者获得至高无上的控制权。这种钥匙并非实体…

作者头像 李华