共计 997 个字符,预计需要花费 3 分钟才能阅读完成。
Java 的 java.util.concurrent
包除了提供底层锁、并发集合外,还提供了一组原子操作的封装类,它们位于 java.util.concurrent.atomic
包。
我们以 AtomicInteger
为例,它提供的主要操作有:
- 增加值并返回新值:
int addAndGet(int delta)
- 加 1 后返回新值:
int incrementAndGet()
- 获取当前值:
int get()
- 用 CAS 方式设置:
int compareAndSet(int expect, int update)
Atomic 类是通过无锁(lock-free)的方式实现的线程安全(thread-safe)访问。它的主要原理是利用了 CAS:Compare and Set。
如果我们自己通过 CAS 编写incrementAndGet()
,它大概长这样:
public int incrementAndGet(AtomicInteger var) {int prev, next;
do {prev = var.get();
next = prev + 1;
} while (! var.compareAndSet(prev, next));
return next;
}
CAS 是指,在这个操作中,如果 AtomicInteger
的当前值是 prev
,那么就更新为next
,返回true
。如果AtomicInteger
的当前值不是 prev
,就什么也不干,返回false
。通过 CAS 操作并配合do ... while
循环,即使其他线程修改了 AtomicInteger
的值,最终的结果也是正确的。
我们利用 AtomicLong
可以编写一个多线程安全的全局唯一 ID 生成器:
class IdGenerator {AtomicLong var = new AtomicLong(0);
public long getNextId() {return var.incrementAndGet();}
}
通常情况下,我们并不需要直接用 do ... while
循环调用 compareAndSet
实现复杂的并发操作,而是用 incrementAndGet()
这样的封装好的方法,因此,使用起来非常简单。
在高度竞争的情况下,还可以使用 Java 8 提供的 LongAdder
和LongAccumulator
。
小结
使用 java.util.concurrent.atomic
提供的原子操作可以简化多线程编程:
- 原子操作实现了无锁的线程安全;
- 适用于计数器,累加器等。
正文完
星哥玩云-微信公众号