返回
敢问LongAdder的计数器放在哪里?
后端
2023-09-14 13:05:28
Java并发编程之LongAdder源码(三)
有人可能会问,既然LongAdder是基于CAS实现的,那么它的计数器放在哪里呢?
答案是:计数器放在Cell
类中。
public final class LongAdder extends Striped64 {
/*
* A padded cell for distributing/combining values across threads in a
* mildly scalable fashion. The first volatile read/write pair is
* relatively expensive (initially), but thereafter the cost is
* minimal.
*
* The Cell object is used only to box the long value; this makes
* the writeValue/getAndAdd methods callable from any thread,
* without requiring allocation or *volatile* declaration.
*
* Updating via CAS is expected to fail some of the time with a
* small overhead, but less so than (for example) boxing the long
* in each call.
*/
@sun.misc.Contended
final class Cell {
volatile long value;
Cell(long x) { value = x; }
final long getValue() { return value; }
final void setValue(long x) { value = x; }
final long getAndAdd(long x) {
long current, next;
do {
current = getValue();
next = current + x;
} while (!UNSAFE.compareAndSwapLong(this, valueOffset, current, next));
return current;
}
final long getAndIncrement() {
return getAndAdd(1L);
}
final long getAndDecrement() {
return getAndAdd(-1L);
}
final long getAndInvert() {
long current, next;
do {
current = getValue();
next = ~current;
} while (!UNSAFE.compareAndSwapLong(this, valueOffset, current, next));
return current;
}
final long compareAndSwap(long expected, long x) {
return UNSAFE.compareAndSwapLong(this, valueOffset, expected, x)
? value : expected;
}
}
}
Cell
类是一个内部类,它继承了Number
类,实现了AtomicLongFieldUpdater
接口。Cell
类的对象可以原子地更新其包含的long值,并且它具有与volatile变量相同的可见性保证。
Cell
类还提供了get
、set
和compareAndSet
方法,用于获取、设置和比较其包含的long值。
值得注意的是,Cell
类使用了@sun.misc.Contended
注解。该注解告诉JVM,Cell
类的对象应该在不同的缓存行中分配。这有助于减少因多个线程同时访问同一个Cell
对象而导致的竞争。
LongAdder类的sum
方法使用Cell
类的对象来存储计数器。当调用sum
方法时,LongAdder
类会创建一个Cell
对象并将其存储在base
字段中。然后,LongAdder
类会调用Cell
对象的getAndAdd
方法来更新计数器。
Cell
类的getAndAdd
方法使用CAS操作来更新计数器。CAS操作可以保证,只有一个线程能够同时更新计数器。这避免了因多个线程同时更新计数器而导致的数据不一致问题。