为什么将整数转换为int再转换为Integer比直接将int转换为Integer快10倍?

3

我有两个大小相同的数组和两种方法。

public class Client {
    private static int[] ints;
    private static final int COUNT = 10000000;
    private static Integer[] integers;

    public static void main(String[] args) {
        Random rand = new Random();
        integers = new Integer[COUNT];
        for (int i = 0; i < integers.length; i++) {
            integers[i] = rand.nextInt();
        }

        ints = new int[COUNT];
        for (int i = 0; i < ints.length; i++) {
            ints[i] = rand.nextInt();
        }

        primitiveToObject();
        objectsToPrimitiveToObject();
    }

    public static  void primitiveToObject() {
        long start = new Date().getTime();
        List<Integer> objects = new ArrayList<>(ints.length);
        for (int i = 0; i < ints.length; i++) {
            int value = ints[i] + 1;
            objects.add(value);          //Boxing
        }
        System.out.println("prim -> object = " + (new Date().getTime() - start));
    }

    public static void objectsToPrimitiveToObject() {
        long start = new Date().getTime();
        List<Integer> result= new ArrayList<>(integers.length);
        for (int i = 0; i < integers.length; i++) {
            int value = integers[i] + 1; //Unboxing
            result.add(value);           //Boxing
        }
        System.out.println("obj -> prim -> object = " + (new Date().getTime() - start));
    }
}

为什么使用装箱与拆箱实现的 objectsToPrimitiveToObject() 比未使用拆箱的 primitiveToObject() 快10倍?


1
你提到的那件事很有趣!你能把你的发现发出来吗?我也想看看。 - Rahul
3
你能否发布你的基准测试代码和结果? - benzonico
尝试对您的基准进行一些小改变,例如交换测试顺序,在代码中重新排列或对实际代码进行更改。结果稳定吗? - Patricia Shanahan
我正在使用JUnit进行基准测试,这可以给出稳定的结果。http://pastie.org/7089667 稍等一下,我会尝试不用JUnit来检查它。 - Nelson Tatius
1
无法重现。 热身后,它们在我的JVM上花费的时间相同。 - NPE
没有使用JUnit进行检查,现在速度提高了3倍。 - Nelson Tatius
1个回答

3

我觉得这可能是因为你对代码的基准测试方式有所偏差。

我已经使用JVM 1.7.0_09-XX:+AggressiveOpts -XX:CompileThreshold=1运行了以下基准测试:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Main {
    static final int COUNT = 1000000;
    static int[] ints = new int[COUNT];
    static Integer[] integers = new Integer[COUNT];

    static void primitiveToObject() {
        List<Integer> objects = new ArrayList<Integer>(ints.length);
        for (int i = 0; i < ints.length; i++) {
            int value = ints[i] + 1;
            objects.add(value);                    //boxing
        }
    }

    static void objectsToPrimitiveToObject() {
        List<Integer> result= new ArrayList<Integer>(integers.length);
        for (int i = 0; i < integers.length; i++) {
            int value = integers[i] + 1;           //unboxing
            result.add(value);                     //boxing
        }
    }

    public static void main(String[] args) {
        Random rand = new Random();
        for (int i = 0; i < COUNT; ++i) {
            int val = rand.nextInt();
            ints[i] = val;
            integers[i] = val;
        }
        for (int i = 0; i < 10; ++i) {
            long start_p = System.currentTimeMillis();
            for (int j = 0; j < 100; ++j) {
                primitiveToObject();
            }
            long end_p = System.currentTimeMillis();
            long start_o = System.currentTimeMillis();
            for (int j = 0; j < 100; ++j) {
                objectsToPrimitiveToObject();
            }
            long end_o = System.currentTimeMillis();
            System.out.printf("p2o:%d o2p2o:%d\n", end_p - start_p, end_o - start_o);
        }
    }
}

以下是结果:
p2o:2043 o2p2o:818
p2o:709 o2p2o:748
p2o:670 o2p2o:756
p2o:675 o2p2o:742
p2o:679 o2p2o:750
p2o:700 o2p2o:757
p2o:738 o2p2o:733
p2o:706 o2p2o:786
p2o:684 o2p2o:752
p2o:676 o2p2o:799

如您所见,在初始预热之后,primitiveToObject() 更快,这是可以预料的,因为该方法执行的工作较少。

为了完整起见,我还使用了JDK 6进行了测试,并观察到类似的结果。


谢谢。我的错误是使用单个调用而不是多次调用每个方法。 - Nelson Tatius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接