Java Collection- ArrayList和Vector之间的加速

时间:2016-03-04 05:38:09

标签: java performance arraylist collections

从某些资源中,我发现在Java集合下,ArrayListVector更快。为了检查这一点,我尝试使用一个小程序,其中一个方法将一些数据添加到ArrayList,然后检索这些数据,另一个方法向Vector添加和检索相同的数据。现在main()方法在两个不同的时间计算过程中调用其中两个,分别计算这些方法的执行时间。在结果中,我得到ArrayList的执行时间是18385831 ns,而Vector的执行时间是2190242 ns。我的项目负责人还说ArrayListVector快。但我的计划的结果是说了不同的东西。有谁可以请原因解释我正确的事情?如果ArrayList真的比Vector快。

,也会导致此结果的原因

这是我的源代码:

import java.util.*;

public class TestArraylist {

    void Arraylistpart() {
        ArrayList<Object> a1 = new ArrayList<Object>();
        ArrayList<Object> a2 = new ArrayList<Object>();
        a2 = a1;

        a1.add(1);
        a1.add('c');
        a1.add("gh");
        a1.add(2);
        a1.set(2, "ab");
        int count = 0;
        System.out.println(a1);
        try {
            for (Object i : a1) {
                a2.set(count, i.toString());
                count = count + 1;
            }
            a2.sort(null);
            System.out.println(a2);
        } catch (ClassCastException e) {
            System.err.println("Exception occurs");
        }
    }

    void vectorpart() {
        Vector<Object> v1 = new Vector<Object>();
        Vector<Object> v2 = new Vector<Object>();
        v2 = v1;
        v1.add(1);
        v1.add('c');
        v1.add("ab");
        v1.add(2);
        int count1 = 0;
        System.out.println(v1);
        try {
            for (Object i : v1) {
                v2.setElementAt(i.toString(), count1);
                count1 = count1 + 1;
            }
            v2.sort(null);
            System.out.println(v2);
        } catch (ClassCastException e) {
            System.err.println("Exception occurs");
        }
    }

    public static void main(String[] args) {
        TestArraylist objct = new TestArraylist();
        System.out.println("Arraylist program");
        long startmili = System.currentTimeMillis();
        long starttime = System.nanoTime();
        objct.Arraylistpart();
        long endtime = System.nanoTime();
        long endmili = System.currentTimeMillis();
        long totaltime = endtime - starttime;
        long totaltimemili = endmili - startmili;
        System.out.println(totaltime);
        System.out.println("Time in mili is: " + totaltimemili);

        System.out.println("\nVector program");
        long startmili1 = System.currentTimeMillis();
        long starttime1 = System.nanoTime();
        objct.vectorpart();
        long endtime1 = System.nanoTime();
        long endmili1 = System.currentTimeMillis();
        long totaltime1 = endtime1 - starttime1;
        long totaltimemili1 = endmili1 - startmili1;
        System.out.println(totaltime1);
        System.out.println("Time in mili is: " + totaltimemili1);
    }
}

2 个答案:

答案 0 :(得分:2)

您的基准测试是错误的。首先,您不仅测量了基于阵列/矢量的操作的时间,而且还测量了打印的时间,这些打印的时间可能比其他所有操作的速度慢几个。其次,你没有进行预热,所以你的大部分代码都可能由解释器执行,而不是JIT编译。第三,在同一个JVM中启动两个测试,将它们置于不同的条件下:在第一次测试执行期间,JVM执行更多预热步骤(例如JIT编译),因此第一个测试从一开始就受到限制。让我们尝试使用JMH

写一些等价物
import org.openjdk.jmh.annotations.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Warmup(iterations = 20, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 20, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(1)
@State(Scope.Benchmark)
public class TestArraylist {

    @Benchmark
    public String Arraylistpart() {
        ArrayList<Object> a1 = new ArrayList<>();
        ArrayList<Object> a2 = new ArrayList<>();
        a2 = a1;

        a1.add(1);
        a1.add('c');
        a1.add("gh");
        a1.add(2);
        a1.set(2, "ab");
        int count = 0;
        for (Object i : a1) {
            a2.set(count, i.toString());
            count = count + 1;
        }
        a2.sort(null);
        return a1.toString()+a2.toString();
    }

    @Benchmark
    public String vectorpart() {
        Vector<Object> v1 = new Vector<>();
        Vector<Object> v2 = new Vector<>();
        v2 = v1;
        v1.add(1);
        v1.add('c');
        v1.add("ab");
        v1.add(2);
        int count1 = 0;
        for (Object i : v1) {
            v2.setElementAt(i.toString(), count1);
            count1 = count1 + 1;
        }
        v2.sort(null);
        return v1.toString()+v2.toString();
    }
}

我返回a1.toString()+a2.toString()而不是打印以保留.toString()次调用(在System.out.println内的测试中完成)。

摘要结果如下:

Benchmark                    Mode  Cnt  Score   Error  Units
TestArraylist.Arraylistpart  avgt   20  0,382 ± 0,003  us/op
TestArraylist.vectorpart     avgt   20  0,421 ± 0,002  us/op

看,你的测试实际上表现得更快,更快。仅382纳秒和421纳秒。由于额外的同步,矢量确实有点慢。但似乎C2 JIT编译器在删除一些不必要的同步部分方面做得很好,因此时差不是很大。检查每次迭代统计数据也很有趣。对于ArrayList

# Warmup Iteration   1: 0,544 us/op
# Warmup Iteration   2: 0,471 us/op
# Warmup Iteration   3: 0,383 us/op
# Warmup Iteration   4: 0,377 us/op
# Warmup Iteration   5: 0,377 us/op
# Warmup Iteration   6: 0,373 us/op
...
Iteration  14: 0,374 us/op
Iteration  15: 0,376 us/op
Iteration  16: 0,381 us/op
Iteration  17: 0,376 us/op
Iteration  18: 0,379 us/op
Iteration  19: 0,383 us/op
Iteration  20: 0,385 us/op

Vector

# Warmup Iteration   1: 0,889 us/op
# Warmup Iteration   2: 0,630 us/op
# Warmup Iteration   3: 0,689 us/op
# Warmup Iteration   4: 0,662 us/op
# Warmup Iteration   5: 0,671 us/op
# Warmup Iteration   6: 0,673 us/op
# Warmup Iteration   7: 0,669 us/op
# Warmup Iteration   8: 0,657 us/op
# Warmup Iteration   9: 0,427 us/op
# Warmup Iteration  10: 0,421 us/op
# Warmup Iteration  11: 0,421 us/op
...
Iteration  17: 0,423 us/op
Iteration  18: 0,420 us/op
Iteration  19: 0,422 us/op
Iteration  20: 0,419 us/op

正如您所看到的,ArrayList在迭代#3上达到了全速,而Vector在迭代#9时达到了它。

答案 1 :(得分:0)

您的基准测试存在多种问题,使Vector看起来比ArrayList更快。要查看它已损坏,只需在执行Vector基准测试之前执行ArrayList benchmkar,然后突然得到相反的结果。

这里列出了在对Java代码进行基准测试时必须记住的事项:

预热代码 - 永远不要对冷代码进行基准测试: JIT优化器在运行时做了一些非常了不起的事情来优化Java代码。但只有在代码执行多次之后才会这样做。性能差异可能非常显着。因此,执行您的基准测试方法几次,而不是测量允许JIT编译器完成其工作的时间。它还确保您所需的所有类都已加载,并且此时间不计入运行时。你的基准测试不会这样做。

确保基准测试运行的时间足够长:在您的基准测试中,只有5个对象被添加到Vector / ArrayList。此代码在大约1毫秒内执行,这太短,无法获得任何有用的结果。如果您的基准测试运行时间不够长,&#34;随机&#34;效果(即线程的调度)会过多地影响结果。尝试添加几百万个元素。

确保使用基准代码的结果:想象一下,您需要预测总计100万个值所需的时间,但您不会对结果做任何事情。 JIT优化器可能会发现您不需要它并丢弃整个计算,这使得基准测试无用。确保您使用结果,例如通过打印它。

如果你想真正认真对待它,还有一些事情要考虑,但这些可能是最重要的。

您可能希望了解一些有助于进行基准测试的框架,例如JMH