为什么Collections :: addAll比ArrayList :: addAll慢但比LinkedList :: addAll快?

时间:2019-08-29 15:08:42

标签: java performance collections

我着手在Javadoc for Collections :: addAll中测试以下声明:

  

此便捷方法的行为与c.addAll(Arrays.asList(elements))相同,但是在大多数实现中,该方法的运行速度可能显着提高。

我使用以下代码测试ArrayList和LinkedList(以及当前集合上的Collections)的addAll的运行时:

public static void main(String[] args) {
  final String LIST_STRING = "ArrayList::addAll";
  Tracker arrTracker = new Tracker(LIST_STRING);
  Tracker colTracker = new Tracker("Collections::addAll");
  final String GREEN = "\u001B[32m";
  final String END_GREEN = "\u001B[0m";
  TimeMeasurer elapsed = new TimeMeasurer();
  Integer[] ints = new Integer[2_000_000];
  for(int i = 0; i < ints.length; i++)
  {
    ints[i] = Integer.valueOf((int) (Math.random()*50_001)-25_000);
  }
  System.out.println("Array filled! "+elapsed);
  List<Integer> collection = new ArrayList<>(List.of(1, 2, 3));
  List<Integer> list = new ArrayList<>(List.of(1, 2, 3));

  System.out.println("Created initial lists. "+elapsed);
  for(int i = 0; i < 4; ++i)
    Collections.addAll(collection,ints);
  System.out.println(GREEN+"Collections::addAll. "+elapsed+END_GREEN);
  collection.clear();
  collection = null;
  for(int i = 0; i < 5; i++)
    System.gc();
  System.out.println("Garbage collected. "+elapsed);
  for(int i = 0; i < 4; ++i)
    list.addAll(Arrays.asList(ints));
  System.out.println(GREEN+LIST_STRING+". "+elapsed+END_GREEN);
  list.clear();
  list = null;
  for(int i = 0; i < 5; i++)
    System.gc();
  System.out.println("Garbage collected. "+elapsed);

  //redoing
  for(int iter = 0; iter < 100; iter++)
  {
    System.out.println();
    collection = new ArrayList<>(List.of(1, 2, 3));
    list = new ArrayList<>(List.of(1, 2, 3));
    System.out.println("Recreated initial lists. "+elapsed);
    for(int i = 0; i < 4; ++i)
      Collections.addAll(collection,ints);
    System.out.println(GREEN+"Collections::addAll. "+colTracker.on(elapsed)+END_GREEN);
    collection.clear();
    collection = null;
    for(int i = 0; i < 5; i++)
      System.gc();
    System.out.println("Garbage collected. "+elapsed);
    for(int i = 0; i < 4; ++i)
      list.addAll(Arrays.asList(ints));
    System.out.println(GREEN+LIST_STRING+". "+arrTracker.on(elapsed)+END_GREEN);
    list.clear();
    list = null;
    for(int i = 0; i < 5; i++)
      System.gc();
    System.out.println("Garbage collected. "+elapsed);
  }
  System.out.println();
  System.out.println(colTracker.average());
  System.out.println(arrTracker.average());
}

出于预热JVM的目的,我忽略了第一次运行,并在测试LinkedList运行时时将= new ArrayList<>(...)更改为= new LinkedList(...)。每个加法运算由200万个随机整数组成,重复4次,总共附加了800万个整数。这是LinkedList的时间测试代码的最终输出:

  

Collections :: addAll:每次运行的平均毫秒数:3586.13
  LinkedList :: addAll:6900.910

的平均每次运行毫秒数

这是ArrayList的时间测试代码的最终输出:

  

Collections :: addAll:354.337
的每次运行平均毫秒数   ArrayList :: addAll:272.990

的平均每次运行毫秒数

所以,这就是我想知道的:

  1. 控制列表类型,为什么LinkedList :: addAll比Collections :: addAll慢得多?
  2. 控制列表类型,为什么ArrayList :: addAll比Collections :: addAll快?

0 个答案:

没有答案