Java面试必备:你使用过Java中的哪些原子类?

Java并发面试题 - 你使用过Java中的哪些原子类?


引言

在Java并发编程中,原子类是一组非常重要的工具,它们提供了一种无锁的线程安全操作方式。本文将介绍Java中常用的原子类及其使用场景,并通过流程图帮助理解其工作原理。

1. 原子类概述

Java中的原子类位于java.util.concurrent.atomic包下,它们利用CAS(Compare-And-Swap)操作实现了非阻塞的线程安全操作,相比传统的synchronized关键字,提供了更好的性能。

成功
失败
线程读取值
计算新值
CAS操作
更新值

2. 基本类型原子类

2.1 AtomicInteger

用于原子操作的整型变量:

AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // 原子递增
counter.getAndAdd(5);     // 先获取当前值再加5

2.2 AtomicLong

用于原子操作的长整型变量:

AtomicLong bigCounter = new AtomicLong(0L);
bigCounter.compareAndSet(0, 100); // 如果当前值为0则设置为100

2.3 AtomicBoolean

用于原子操作的布尔变量:

AtomicBoolean flag = new AtomicBoolean(true);
flag.compareAndSet(true, false); // 如果当前为true则设置为false
相等
不相等
读取当前值
比较期望值
与实际值
更新为新值
操作失败

3. 引用类型原子类

3.1 AtomicReference

用于原子操作的引用类型:

AtomicReference<String> ref = new AtomicReference<>("initial");
ref.compareAndSet("initial", "updated");

3.2 AtomicStampedReference

解决ABA问题的引用类型,带有版本号:

AtomicStampedReference<String> stampedRef = 
    new AtomicStampedReference<>("value", 0);
int[] stampHolder = new int[1];
String oldValue = stampedRef.get(stampHolder);
stampedRef.compareAndSet(oldValue, "newValue", stampHolder[0], stampHolder[0]+1);

3.3 AtomicMarkableReference

与AtomicStampedReference类似,但使用布尔标记而非版本号:

AtomicMarkableReference<String> markableRef = 
    new AtomicMarkableReference<>("value", false);
boolean[] markHolder = new boolean[1];
String current = markableRef.get(markHolder);
markableRef.compareAndSet(current, "newValue", markHolder[0], !markHolder[0]);

4. 数组原子类

4.1 AtomicIntegerArray

原子操作的整型数组:

AtomicIntegerArray array = new AtomicIntegerArray(10);
array.incrementAndGet(0); // 原子递增第0个元素

4.2 AtomicLongArray

原子操作的长整型数组:

AtomicLongArray longArray = new AtomicLongArray(10);
longArray.addAndGet(0, 100L); // 原子增加第0个元素100

4.3 AtomicReferenceArray

原子操作的引用类型数组:

AtomicReferenceArray<String> refArray = new AtomicReferenceArray<>(10);
refArray.compareAndSet(0, null, "new value");
创建数组原子类
指定索引操作
执行原子操作
返回结果

5. 字段更新器

5.1 AtomicIntegerFieldUpdater

用于原子更新对象的整型字段:

class MyClass {
    volatile int count;
}

AtomicIntegerFieldUpdater<MyClass> updater = 
    AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "count");
MyClass obj = new MyClass();
updater.incrementAndGet(obj);

5.2 AtomicLongFieldUpdater

用于原子更新对象的长整型字段:

AtomicLongFieldUpdater<MyClass> longUpdater = 
    AtomicLongFieldUpdater.newUpdater(MyClass.class, "longField");

5.3 AtomicReferenceFieldUpdater

用于原子更新对象的引用类型字段:

AtomicReferenceFieldUpdater<MyClass, String> refUpdater = 
    AtomicReferenceFieldUpdater.newUpdater(MyClass.class, String.class, "refField");

6. 累加器类(Java 8+)

6.1 LongAdder

高并发下比AtomicLong性能更好:

LongAdder adder = new LongAdder();
adder.add(10);
long sum = adder.sum();

6.2 DoubleAdder

用于double类型的累加:

DoubleAdder doubleAdder = new DoubleAdder();
doubleAdder.add(1.5);
double sum = doubleAdder.sum();

6.3 LongAccumulator

更通用的累加器,可以自定义操作:

LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);
accumulator.accumulate(100);
accumulator.accumulate(50);
long max = accumulator.get();
创建累加器
多线程并发累加
内部使用单元格分散竞争
最终合并结果

7. 使用场景对比

场景推荐类原因
简单计数器AtomicInteger/AtomicLong简单易用
高并发计数器LongAdder/DoubleAdder性能更好
对象引用更新AtomicReference通用引用更新
需要解决ABA问题AtomicStampedReference带版本控制
数组元素原子操作AtomicXxxArray数组专用
已有类字段原子更新AtomicXxxFieldUpdater无需修改类结构

8. 总结

Java的原子类提供了一种高效的线程安全操作方式,避免了锁带来的性能开销。选择合适的原子类需要根据具体场景:

  1. 基本类型操作选择对应的AtomicXxx
  2. 高并发计数选择LongAdder/DoubleAdder
  3. 引用类型操作选择AtomicReference及其变种
  4. 数组操作选择AtomicXxxArray
  5. 已有类字段更新选择AtomicXxxFieldUpdater
基本类型
引用类型
高并发计数
数组操作
字段更新
需要原子操作?
操作类型
AtomicInteger/AtomicLong/AtomicBoolean
AtomicReference
LongAdder/DoubleAdder
AtomicXxxArray
AtomicXxxFieldUpdater
考虑ABA问题?
AtomicStampedReference
继续使用

通过合理使用这些原子类,可以显著提高Java并发程序的性能和可靠性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值