Почему время выполнения программы каждый раз разное и иногда Vector работает якобы быстрее, чем ArrayList?
Решил проверить, насколько быстрее несинхронизированный ArrayList, чем потокобезопасный Vector. Для замера потраченного времени использовал System.nanoTime()
. Написал метод:
private static void battleOfArrayListAndVector() {
System.out.println("--------------------------------------------------");
System.out.println("Битва: Vector vs. ArrayList:");
long startTime = System.nanoTime();
Vector<String> vector = new Vector<>();
vector.add("Java");
vector.add("C++");
vector.add(1, "C");
vector.add(null);
vector.add("");
vector.addAll(Arrays.asList("Python", "JavaScript", "HTML", "CSS"));
vector.remove(vector.size() - 1);
vector.removeAll(Arrays.asList(null, ""));
vector.retainAll(Arrays.asList("Java", "C++"));
System.out.println("Есть элемент \"PHP\"? " + vector.contains("PHP"));
long endTime = System.nanoTime();
long vectorTime = endTime - startTime;
System.out.println("Vector потратил " + vectorTime + " наносекунд");
startTime = System.nanoTime();
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("C++");
arrayList.add(1, "C");
arrayList.add(null);
arrayList.add("");
arrayList.addAll(Arrays.asList("Python", "JavaScript", "HTML", "CSS"));
arrayList.remove(vector.size() - 1);
arrayList.removeAll(Arrays.asList(null, ""));
arrayList.retainAll(Arrays.asList("Java", "C++"));
System.out.println("Есть элемент \"PHP\"? " + arrayList.contains("PHP"));
endTime = System.nanoTime();
long arrayListTime = endTime - startTime;
System.out.println("ArrayList потратил " + arrayListTime + " наносекунд");
System.out.println("ArrayList сэкономил: " + (vectorTime - arrayListTime) + " наносекунд.");
System.out.println("--------------------------------------------------");
}
Запустил несколько раз и обнаружил, что время каждый раз меняется, при чём очень сильно. Иногда даже получается, что Vector быстрее. Вот вывод с трёх запусков этого метода:
(1)
--------------------------------------------------
Битва: Vector vs. ArrayList:
Есть элемент "PHP"? false
Vector потратил 3994242 наносекунд
Есть элемент "PHP"? false
ArrayList потратил 3300205 наносекунд
ArrayList сэкономил: 694037 наносекунд.
--------------------------------------------------
(2)
--------------------------------------------------
Битва: Vector vs. ArrayList:
Есть элемент "PHP"? false
Vector потратил 4024390 наносекунд
Есть элемент "PHP"? false
ArrayList потратил 3704312 наносекунд
ArrayList сэкономил: 320078 наносекунд.
--------------------------------------------------
(3)
--------------------------------------------------
Битва: Vector vs. ArrayList:
Есть элемент "PHP"? false
Vector потратил 1880058 наносекунд
Есть элемент "PHP"? false
ArrayList потратил 3483657 наносекунд
ArrayList сэкономил: -1603599 наносекунд.
--------------------------------------------------
В последнем случае ArrayList вообще оказался медленней. Как так? Почему время исполнения программы постоянно меняется и иногда вместе с выводом исследования?
Ответы (1 шт):
Вкратце, ArrayList работает быстрее вектора, просто я накосячил. Немного переписал код проверки, прогнав тест 10000 раз, чтобы узнать, сколько раз ArrayList выигрывает. Получилось, что где-то около 7750 из 10000.
Как я понял, JVM "занимается" своими внутренними процессами (например, сборка мусора) и это фальсифицирует результаты.
Решение проблемы:
- Добавил вызов
System.gc()
для предотвращения активности garbage collector'а — это рекомендация отсюда. - По совету @NowhereMan вынес создание листов для запусков метода
addAll()
в отдельные статические переменные. - Закрыл все сторонние программы, оставил только командную строку, которая нужна для запуска.
- Запустил программу с флагами
-Xbatch
и-Xcomp
, чтобы JVM не вздумала оптимизировать работу программы каждый раз:
java -Xbatch -Xcomp theory/collections/UseVector
В результате ArrayList стал выигрывать в 9996 и более случаях из десяти тысяч. Иногда даже до максимума доходило.
Финальный код:
public static void battleOfVectorAndArrayList() {
int counterOfArrayListWins = 0;
for(int i = 0; i < 10000; i++) {
System.gc();
long time = getWinOfArrayList();
if(time > 0) counterOfArrayListWins++;
}
System.out.println("ArrayList выиграл " + counterOfArrayListWins + " раз.");
}
private static List<String> list1 = Arrays.asList("Python", "JavaScript", "HTML", "CSS");
private static List<String> list2 = Arrays.asList("", null);
private static List<String> list3 = Arrays.asList("Java", "C++");
private static long getWinOfArrayList() {
long startTime = System.nanoTime();
Vector<String> vector = new Vector<>();
vector.add("Java");
vector.add("C++");
vector.add(1, "C");
vector.add(null);
vector.add("");
vector.addAll(list1);
vector.remove(vector.size() - 1);
vector.removeAll(list2);
vector.retainAll(list3);
long endTime = System.nanoTime();
long vectorTime = endTime - startTime;
startTime = System.nanoTime();
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("C++");
arrayList.add(1, "C");
arrayList.add(null);
arrayList.add("");
arrayList.addAll(list1);
arrayList.remove(arrayList.size() - 1);
arrayList.removeAll(list2);
arrayList.retainAll(list3);
endTime = System.nanoTime();
long arrayListTime = endTime - startTime;
return vectorTime - arrayListTime;
}