AtomicInteger实现和代码重复 [英] AtomicInteger implementation and code duplication

查看:65
本文介绍了AtomicInteger实现和代码重复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

警告:问题有点长,但分隔线下方的部分仅用于好奇。

Oracle的JDK 7实施 AtomicInteger 包含以下内容方法:

Oracle's JDK 7 implementation of AtomicInteger includes the following methods:

public final int addAndGet(int delta) {
    for (;;) {
        int current = get();
        int next = current + delta;         // Only difference
        if (compareAndSet(current, next))
            return next;
    }
}

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;             // Only difference
        if (compareAndSet(current, next))
            return next;
    }
}

似乎很清楚,第二种方法可能已被写入:

It seems clear that the second method could have been written:

public final int incrementAndGet() {
    return addAndGet(1);
}

该类中还有其他几个类似代码重复的例子。我想不出有任何理由这样做,而是考虑性能因素(*)。我很确定作者在确定设计之前做了一些深入的测试。

There are several other examples of similar code duplication in that class. I can't think of any reasons to do that but performance considerations (*). And I am pretty sure the authors did some in-depth testing before settling on that design.

为什么(或在什么情况下)第一个代码表现更好比第二个?

(*)我忍不住写了一个快速的微基准。它显示(后JIT)系统性差距为2-4%,有利于 addAndGet(1) vs incrementAndGet()(这无疑是小的,但它非常一致)。我无法真实地解释这个结果,说实话......

(*) I could not resist but write a quick micro benchmark. It shows (post-JIT) a systematic gap of 2-4% performance in favour of addAndGet(1) vs incrementAndGet() (that is admittedly small, but it is very consistent). I can't really explain that result either to be honest...

输出:


incrementAndGet():905

addAndGet(1):868

incrementAndGet():902

addAndGet(1):863

incrementAndGet():891

addAndGet(1):867

...

incrementAndGet(): 905
addAndGet(1): 868
incrementAndGet(): 902
addAndGet(1): 863
incrementAndGet(): 891
addAndGet(1): 867
...

代码:

public static void main(String[] args) throws Exception {
    final int size = 100_000_000;
    long start, end;
    AtomicInteger ai;

    System.out.println("JVM warmup");
    for (int j = 0; j < 10; j++) {
        start = System.nanoTime();
        ai = new AtomicInteger();
        for (int i = 0; i < size / 10; i++) {
            ai.addAndGet(1);
        }
        end = System.nanoTime();
        System.out.println("addAndGet(1): " + ((end - start) / 1_000_000));
        start = System.nanoTime();
        ai = new AtomicInteger();
        for (int i = 0; i < size / 10; i++) {
            ai.incrementAndGet();
        }
        end = System.nanoTime();
        System.out.println("incrementAndGet(): " + ((end - start) / 1_000_000));
    }


    System.out.println("\nStart measuring\n");

    for (int j = 0; j < 10; j++) {
        start = System.nanoTime();
        ai = new AtomicInteger();
        for (int i = 0; i < size; i++) {
            ai.incrementAndGet();
        }
        end = System.nanoTime();
        System.out.println("incrementAndGet(): " + ((end - start) / 1_000_000));
        start = System.nanoTime();
        ai = new AtomicInteger();
        for (int i = 0; i < size; i++) {
            ai.addAndGet(1);
        }
        end = System.nanoTime();
        System.out.println("addAndGet(1): " + ((end - start) / 1_000_000));
    }
}


推荐答案

我我会给出新的假设。如果我们查看 AtomicInteger 的字节代码,我们会看到它们之间的主要区别在于 addAndGet 使用 iload _ 指令, incrementAndGet 使用 iconst _ 指令:

I'll give new supposition. If we look into byte code of AtomicInteger we will see, that the main difference between them is that addAndGet uses iload_ instruction, and incrementAndGet uses iconst_ instruction:

public final int addAndGet(int);
   ...
   4:   istore_2
   5:   iload_2
   6:   iload_1
   7:   iadd

public final int incrementAndGet();
   ...
   4:   istore_1
   5:   iload_1
   6:   iconst_1
   7:   iadd

看来, iconst _ + iadd 翻译为 INC 指令,由于 iload _ ... iadd as ADD 指令。这一切都涉及关于 ADD 1 vs INC 等众所周知的问题,依此类推:

It seems, that iconst_+iadd translates as INC instruction, due to iload_...iadd as ADD instruction. This all relates to commonly known question about ADD 1 vs INC and so on:

x86 inc与add指令的相对性能

ADD 1真的比INC快吗? x86

这可能就是答案,为什么 addAndGet 略快于 incrementAndGet

This could be the answer, why addAndGet is slightly faster than incrementAndGet

这篇关于AtomicInteger实现和代码重复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆