双倍效率提升!10行代码改造AtomicRangeInteger

801 阅读1分钟

最近看skywalking源码 发现有一个原子类数据结构性能提升明显 10行代码 效率提升一倍 所以详细研究了一下

需求

一个原子Integer类型,范围在startValue和endValue间变化

旧的原子类

    public final int getAndIncrement() {
        int current;
        int next;
        do {
            current = this.value.get();
            next = current >= this.endValue ? this.startValue : current + 1;
        }
        while (!this.value.compareAndSet(current, next));

        return current;
    }

新的原子类

    public final int getAndIncrement() {
        int next;
        do {
            next = this.value.incrementAndGet();
            if (next > endValue && this.value.compareAndSet(next, startValue)) {
                return endValue;
            }
        } while (next > endValue);

        return next - 1;
    }

性能提升

使用Junit的Benchmark对比,我们发现

* Benchmark                                                  Mode  Cnt         Score         Error  Units
* AtomicRangeIntegerTest.testNewGetAndIncrementPerformance  thrpt    5  41474285.923 ± 3595500.827  ops/s
* AtomicRangeIntegerTest.testOriGetAndIncrementPerformance  thrpt    5  14199415.907 ± 1697559.657  ops/s

ops从170k增加到360k 性能翻倍

原理分析

通过源码前后变化我们可以发现 旧代码中每次都要通过compareAndSet去更新值,有很多缺点 1 冲突概率大大增加(步骤增多,冲突概率增多) 2 乐观锁自旋损耗性能(do while循环) 而新代码每次利用原子类AtomicInteger自增 减小了冲突概率 降低了锁的消耗 只在到达endValue时才会compareAndSet 并且while循环多数情况下只循环一次 所以说多看源码 看大神优化可以提高自己对并发类的认识