面试题答案
一键面试AtomicInteger利用CAS实现线程安全操作
- CAS(Compare - and - Swap)原理:
- CAS是一种硬件原语,它包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。只有当内存位置V的值与预期原值A相匹配时,才会将内存位置V的值更新为新值B,否则不执行任何操作。
- 在
AtomicInteger
中,例如incrementAndGet
方法,其底层是通过unsafe.compareAndSwapInt
来实现的。AtomicInteger
内部有一个volatile
修饰的value
字段存储实际的整数值。 - 当执行
incrementAndGet
时,它会不断尝试使用CAS将value
的值加1。具体过程如下:- 首先获取当前
value
的值(假设为curValue
)。 - 然后计算新值
newValue = curValue + 1
。 - 调用
unsafe.compareAndSwapInt(this, valueOffset, curValue, newValue)
,这里this
是AtomicInteger
实例,valueOffset
是value
字段在内存中的偏移量。如果当前value
的值仍然是curValue
(即没有其他线程修改过),则将value
更新为newValue
;如果value
的值已经改变,那么CAS操作失败,重新获取当前value
的值并重复上述过程,直到CAS操作成功。
- 首先获取当前
- 代码示例:
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(0);
int result = atomicInteger.incrementAndGet();
System.out.println("Incremented value: " + result);
}
}
Atomic类与Java内存模型特性关联及相互作用
- volatile语义:
AtomicInteger
中的value
字段被声明为volatile
。volatile
关键字保证了不同线程对value
的可见性。- 当一个线程修改了
value
的值,由于volatile
的存在,其他线程能够立即看到这个修改。这是因为volatile
变量在写操作时会将修改后的值立即刷新到主内存,读操作时会直接从主内存读取最新的值,而不是从线程的本地缓存中读取旧值。 - 例如,在
AtomicInteger
的set
方法中,直接对volatile
修饰的value
进行赋值,其他线程随后读取value
时能获取到最新值。
- 内存屏障:
- Java内存模型通过内存屏障来保证不同线程间操作的顺序性。
volatile
变量的读写操作会插入内存屏障。 - 对于
AtomicInteger
,当执行incrementAndGet
等操作时,由于value
是volatile
的,在对value
进行CAS操作前后会插入内存屏障。写操作前的内存屏障会确保写操作之前的所有操作都完成并对其他线程可见,读操作后的内存屏障会确保读操作之后的所有操作在获取到最新的value
值之后才执行。 - 例如,假设一个线程在修改
AtomicInteger
的value
之前有一些其他计算操作,写操作前的内存屏障保证这些计算操作的结果对其他线程可见,这样其他线程在读取value
时,不会因为缓存不一致等问题而读取到错误的结果。同时,读操作后的内存屏障保证后续基于读取到的value
值的操作是在获取到最新值之后进行的。
- Java内存模型通过内存屏障来保证不同线程间操作的顺序性。
综上所述,AtomicInteger
通过CAS硬件原语实现原子性操作,借助volatile
语义保证可见性,利用内存屏障保证操作顺序性,从而在多线程环境下实现线程安全的操作,其他Atomic类的实现原理与AtomicInteger
类似。