返回

敢问LongAdder的计数器放在哪里?

后端

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类还提供了getsetcompareAndSet方法,用于获取、设置和比较其包含的long值。

值得注意的是,Cell类使用了@sun.misc.Contended注解。该注解告诉JVM,Cell类的对象应该在不同的缓存行中分配。这有助于减少因多个线程同时访问同一个Cell对象而导致的竞争。

LongAdder类的sum方法使用Cell类的对象来存储计数器。当调用sum方法时,LongAdder类会创建一个Cell对象并将其存储在base字段中。然后,LongAdder类会调用Cell对象的getAndAdd方法来更新计数器。

Cell类的getAndAdd方法使用CAS操作来更新计数器。CAS操作可以保证,只有一个线程能够同时更新计数器。这避免了因多个线程同时更新计数器而导致的数据不一致问题。