值比较和值赋值之间是否存在性能差异?

时间:2013-01-05 20:30:42

标签: java performance optimization jvm atomic

考虑以下两个代码示例:

示例1。

public void setValue(int value)
{
    mValue = value;
}

示例2。

public void setValue(int value)
{
    if (mValue != value)
    {
        mValue = value;
    }
}

假装你的任务是将一些Java代码优化到绝对最大值,超越所有常识。

第二个代码示例是第一个的优化吗?我的意思是,在最低级别的Java或JVM中if条件检查和int赋值之间是否存在任何差异(无论多么微小)?

4 个答案:

答案 0 :(得分:9)

第二种可能是反优化,因为在现代处理器上,分支往往很昂贵(主要是因为branch misprediction成本极高)。

确定的唯一方法是在代表性输入上分析您的代码。有关如何设置有意义的微观基准的一些指示,请参阅How do I write a correct micro-benchmark in Java?

请记住,如果相关代码不占整个CPU时间的很大一部分,那么全世界的所有优化都不会对应用程序的整体性能产生很大影响。

答案 1 :(得分:3)

NPE有很好的建议。我要添加的一条评论可能还取决于mValue是否是易变的,以及您正在运行它的硬件。对于挥发性物质,写入可能比读取数倍贵。一些硬件(我相信许多移动设备,例如)易失性读取相当便宜,因此差异可能会下降。

答案 2 :(得分:1)

您可以尝试编译两者,然后使用java字节码反汇编程序来检查差异。 Wikipedia JVM instruction listings可能是一个很好的起点。

根据我对我使用过的编译器和虚拟机的理解,由于额外的比较操作,第二个代码片段可能会慢一点(。微小)。

如果您的JVM实现有一个优化器,它可能会将您的第一个代码示例减少到一个操作,而第二个代码段将需要至少一个或两个操作来考虑比较操作。

答案 3 :(得分:0)

良好的编码实践说:“在最后一刻之前延迟优化”

但代码测试说:

  • TOTAL(1)= 1000000000 1420ms TOTAL(2)= 1000000000 2155ms
  • TOTAL(1)= 1000000000 1374ms TOTAL(2)= 1000000000 1884ms
  • TOTAL(1)= 1000000000 1379ms TOTAL(2)= 1000000000 2072ms

比较&设置不是更好。

// Test Code
public class CompareAndSet {
    int mValue;

    // 1
    public void setValue1(int value) {
        mValue = value;
    }

    // 2
    public void setValue2(int value) {
        if (mValue != value) {
            mValue = value;
        }
    }

    public static void main(String[] args) {
        final int TOTAL = (int) 1e9;
        long ts;
        for (int j = 0; j < 3; j++) {
            // 1
            {
                ts = System.currentTimeMillis();
                CompareAndSet cs = new CompareAndSet();
                for (int i = 0; i < TOTAL; i++) {
                    cs.setValue1(i);
                }
                System.out.println("TOTAL(1)=" + TOTAL + " "
                        + (System.currentTimeMillis() - ts) + "ms");
            }
            // 2
            {
                ts = System.currentTimeMillis();
                CompareAndSet cs = new CompareAndSet();
                for (int i = 0; i < TOTAL; i++) {
                    cs.setValue2(i);
                }
                System.out.println("TOTAL(2)=" + TOTAL + " "
                        + (System.currentTimeMillis() - ts) + "ms");
            }
        }
    }

}