深入理解Java并发编程中的原子操作、volatile关键字与读写锁
1. 原子操作与AtomicInteger等原子类
1.1 原子操作的原理
在多线程环境中,多个线程可能会同时访问和修改共享资源。如果这些操作不是原子性的(即可以被中断),那么可能会导致数据不一致或竞态条件(race condition)。原子操作是指不可分割的操作,即在多线程环境下,这些操作不会被其他线程打断。
Java提供了java.util.concurrent.atomic
包来支持原子操作,底层通过CPU提供的CAS(Compare-And-Swap)指令实现。CAS是一种无锁算法,它通过比较内存位置的值是否等于预期值,如果是,则更新为新值;否则,重试直到成功。
CAS的优点:
- 避免了传统锁机制带来的阻塞问题。
- 提高了并发性能,特别是在竞争不激烈的情况下。
CAS的缺点:
- ABA问题:当一个变量从A变为B再变回A时,CAS会误认为没有变化。
- 循环时间长开销大:如果CAS操作失败,需要不断重试,可能导致较高的CPU开销。
1.2 AtomicInteger类详解
AtomicInteger
是Java中常用的原子类之一,它提供了一系列原子操作方法,如get()
、set()
、incrementAndGet()
、decrementAndGet()
等。这些方法确保了在多线程环境下的线程安全性。
常用方法:
int get()
: 获取当前值。void set(int newValue)
: 设置为给定值。int incrementAndGet()
: 将当前值加1并返回新的值。int decrementAndGet()
: 将当前值减1并返回新的值。int addAndGet(int delta)
: 将当前值增加指定的增量并返回新的值。boolean compareAndSet(int expect, int update)
: 如果当前值等于预期值,则设置为新值,并返回true;否则返回false。
示例代码:
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.incrementAndGet();
}
});
Thread t2 =