TOP 带着问题看源码
- 有了 AtomicLong 为什么还会有 LongAdder
1. 基本介绍
LongAdder 是一个线程安全,JDK 8新加入的一个用来计数的工具类
按照作者的说法,LongAdder 在多个线程更新下比 AtomicLong 性能更好,但要消耗更多的空间
LongAdder 继承自 Striped64,其对一些简单情况做了处理(cell 存在且更新没有竞争),复杂情况交给 Striped64 的 longAccumulate。
2. Striped64
Striped64 设计思路是把多个线程分散到不同计数单元,减少线程竞争,提高并发效率
2.1 成员变量分析
1 | // 可用 CPU 数量 |
2.2 Cell 类分析
1 | static final class Cell { .misc.Contended |
Cell
类是 Striped64
的静态内部类。通过注解 [@sun.misc.Contended](mailto:
@sun.misc.Contended)` 来自动实现缓存行填充,让 Java 编译器和 JRE 运行时来决定如何填充。本质上是一个填充了的、提供了 CAS 更新的 volatile 变量。
2.3 longAccumulate() 分析
1 | final void longAccumulate(long x, LongBinaryOperator fn, |
3. add() 分析
1 | public void add(long x) { |
4. sum() 分析
熟悉 ConcurrentHashMap 的同鞋看到 sum 相比已经很熟悉,惰性按需计算,可能会不太精准
1 | public long sum() { |
5. reset() 分析
遍历 cells 数组,重置为0
1 | public void reset() { |
总结
可以看到 LongAdder 的核心思路就是保证高并发最坏的情况,通过对线程进行散列分片减少竞争时长,利用上了多核的性能。这种设计方式和 CSAPP 中 提高并行性 提到的方式是一样的。
回到开篇 TOP 1 问题,可以看到 LongAdder 主要目的是解决高并发下 AtomicLong 自旋开销问题 。