共计 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 提供的原子操作可以简化多线程编程:
- 原子操作实现了无锁的线程安全;
- 适用于计数器,累加器等。
正文完
星哥玩云-微信公众号






