回答
作为一个模拟的 Java 后端工程师,我“使用过” Java 中 java.util.concurrent.atomic
包提供的多种原子类。这些原子类基于 CAS(Compare-And-Swap)操作,提供线程安全的无锁原子操作,广泛应用于高并发场景。以下是我“使用过”的主要原子类及其应用场景的总结:
1. AtomicInteger
- 用途:线程安全的整数计数器。
- 常用方法:
get()
:获取当前值。set(int newValue)
:设置新值。incrementAndGet()
:原子递增并返回新值。compareAndSet(int expect, int update)
:CAS 更新。
- 场景:
- 生成全局唯一 ID。
- 统计请求次数。
- 示例:
输出:import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerExample { private static final AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args) { Runnable task = () -> System.out.println("ID: " + counter.incrementAndGet()); Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); } }
ID: 1 ID: 2
2. AtomicLong
- 用途:线程安全的长整型计数器。
- 常用方法:与
AtomicInteger
类似。 - 场景:
- 处理大范围计数(如时间戳)。
- 高精度统计。
- 示例:累加时间戳。
3. AtomicBoolean
- 用途:线程安全的布尔值。
- 常用方法:
get()
:获取当前值。compareAndSet(boolean expect, boolean update)
:CAS 更新。
- 场景:
- 控制开关(如启动/停止标志)。
- 单次初始化标志。
- 示例:
import java.util.concurrent.atomic.AtomicBoolean; public class AtomicBooleanExample { private static final AtomicBoolean flag = new AtomicBoolean(false); public static void main(String[] args) { if (flag.compareAndSet(false, true)) { System.out.println("Initialized by " + Thread.currentThread().getName()); } } }
4. AtomicReference
- 用途:线程安全的对象引用。
- 常用方法:
get()
:获取当前引用。compareAndSet(V expect, V update)
:CAS 更新引用。
- 场景:
- 无锁数据结构(如链表节点)。
- 单例模式线程安全初始化。
- 示例:
import java.util.concurrent.atomic.AtomicReference; public class AtomicReferenceExample { private static final AtomicReference<String> ref = new AtomicReference<>(); public static void main(String[] args) { ref.compareAndSet(null, "Initialized"); System.out.println("Value: " + ref.get()); } }
5. AtomicIntegerArray
/ AtomicLongArray
/ AtomicReferenceArray
- 用途:线程安全的数组元素操作。
- 常用方法:
get(int index)
:获取指定索引值。compareAndSet(int index, int expect, int update)
:CAS 更新。
- 场景:
- 多线程更新数组元素。
- 统计每个分区的数据。
- 示例:
import java.util.concurrent.atomic.AtomicIntegerArray; public class AtomicIntegerArrayExample { private static final AtomicIntegerArray array = new AtomicIntegerArray(5); public static void main(String[] args) { array.addAndGet(0, 10); System.out.println("Array[0]: " + array.get(0)); // 输出 10 } }
6. LongAdder
和 LongAccumulator
- 用途:
LongAdder
:高并发计数器,分段累加减少争用。LongAccumulator
:更通用的累加器,支持自定义操作。
- 常用方法:
add(long x)
:增加值。sum()
:获取总和。
- 场景:
- 高并发统计(如 QPS、流量计数)。
- 示例:
import java.util.concurrent.atomic.LongAdder; public class LongAdderExample { private static final LongAdder adder = new LongAdder(); public static void main(String[] args) { Thread t1 = new Thread(() -> adder.increment()); Thread t2 = new Thread(() -> adder.increment()); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Sum: " + adder.sum()); // 输出 2 } }
- 特点:比
AtomicLong
在高并发下性能更好。
7. AtomicMarkableReference
和 AtomicStampedReference
- 用途:
AtomicMarkableReference
:带布尔标记的引用。AtomicStampedReference
:带整数戳的引用,解决 ABA 问题。
- 场景:
- 无锁数据结构中防止 ABA 问题。
- 示例:
import java.util.concurrent.atomic.AtomicStampedReference; public class AtomicStampedReferenceExample { private static final AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0); public static void main(String[] args) { int[] stampHolder = {0}; String value = ref.get(stampHolder); ref.compareAndSet("A", "B", stampHolder[0], stampHolder[0] + 1); System.out.println("Value: " + ref.getReference() + ", Stamp: " + ref.getStamp()); } }
使用经验总结
- 常用场景:
AtomicInteger
:计数器、ID 生成。LongAdder
:高并发统计。AtomicReference
:无锁单例。
- 选择依据:
- 低并发:
AtomicInteger
/AtomicLong
足够。 - 高并发:
LongAdder
更优。 - 对象操作:
AtomicReference
或数组类。
- 低并发:
问题分析与知识点联系
“使用过的 Java 原子类”是并发编程中无锁操作的基础,与问题列表中的多个知识点相关:
-
Java 中的线程安全
原子类通过 CAS 保证线程安全,无需显式锁。 -
Java 中的 CAS 操作
原子类的核心机制,compareAndSet
是典型实现。 -
Java 使用过哪些并发工具类
原子类是并发工具的重要组成部分。 -
Java 中的 ABA 问题
AtomicStampedReference
专门解决此问题。 -
Java 的累加器
LongAdder
和LongAccumulator
是高级累加工具。
总结来说,我“使用过”的原子类覆盖了基本计数、对象操作和高并发优化等多种需求。它们基于 CAS 提供高效的无锁操作,是 Java 并发编程中替代锁的重要工具,与线程安全和性能优化密切相关。