硬件环境
CPU: intel 14700KF
内存:ddr5 7600 24g * 2
系统&软件版本
windows11
jdk版本:
openjdk version "11.0.22" 2024-01-16 LTS
OpenJDK Runtime Environment Corretto-11.0.22.7.1 (build 11.0.22+7-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.22.7.1 (build 11.0.22+7-LTS, mixed mode)
测试方法介绍
模拟日常开发中简单的业务场景,一组存在ArrayList中的People对象的年龄>=18,标记为成年人,通过不同的遍历方式实现下面这段代码,并执行一定的次数,可体现出性能差异化的次数,次数过少可能会导致结果太接近。
for (int j = 0; j < cycleTimes; j++) {
for (int i = 0; i < arrayListSize; i++) {
People people = ori.get(i);
if (people.getAge() >= 18) {
people.setIsAdult(true);
}
}
}
完整测试代码
public class TestOthers {
public static class People {
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isAdult() {
return isAdult;
}
public void setIsAdult(boolean adult) {
isAdult = adult;
}
public static Random getRandom() {
return random;
}
public static void setRandom(Random random) {
People.random = random;
}
int age;
boolean isAdult;
public static Random random = new Random();
public People() {
this.age = random.nextInt(120);
}
}
/**
*
* @param arrayListSize 需要遍历的数组的个数
* @param cycleTimes 执行次数,达到一定次数才能看出时间差异
* @param diffLoopTypeTimeList 存储不同类型遍历的时间结果
*/
public static void testPerformance(int arrayListSize, int cycleTimes, Map<String, List<Long>> diffLoopTypeTimeList) {
List<People> ori = new ArrayList<>(arrayListSize);
for (int i = 0; i < arrayListSize; i++) {
ori.add(new People());
}
long t1 = System.currentTimeMillis();
for (int j = 0; j < cycleTimes; j++) {
for (int i = 0; i < arrayListSize; i++) {
People people = ori.get(i);
if (people.getAge() >= 18) {
people.setIsAdult(true);
}
}
}
long t2 = System.currentTimeMillis();
for (int i = 0; i < cycleTimes; i++) {
for (People people : ori) {
if (people.getAge() >= 18) {
people.setIsAdult(true);
}
}
}
long t3 = System.currentTimeMillis();
for (int i = 0; i < cycleTimes; i++) {
ori.stream().filter((ele) -> ele.getAge() >= 18).forEach(ele -> ele.setIsAdult(true));
}
long t4 = System.currentTimeMillis();
for (int i = 0; i < cycleTimes; i++) {
ori.parallelStream().filter((ele) -> ele.getAge() >= 18).forEach(ele -> ele.setIsAdult(true));
}
long t5 = System.currentTimeMillis();
collectResult(diffLoopTypeTimeList, t1, t2, t3, t4, t5);
}
public static void main(String[] args) throws InterruptedException {
HashMap<String, List<Long>> diffLoopTimeList = new HashMap<>();
//用不同方式,遍历200w次含20个元素的数组并做简单的判断和设置值
int times = 1;
for (int i = 0; i < times; i++) {
testPerformance(20, 2000000, diffLoopTimeList);
} for (Map.Entry<String, List<Long>> stringListEntry : diffLoopTimeList.entrySet()) {
System.out.println(stringListEntry.getKey() + " : " + stringListEntry.getValue() + "ms");
}
}
private static void collectResult(Map<String, List<Long>> diffLoopTimeList, long t1, long t2, long t3, long t4, long t5) {
List<Long> aFor = diffLoopTimeList.getOrDefault("for循环", new ArrayList<>(20));
aFor.add(t2 - t1);
diffLoopTimeList.put("for循环", aFor);
List<Long> aForeach = diffLoopTimeList.getOrDefault("foreach循环", new ArrayList<>(20));
aForeach.add(t3 - t2);
diffLoopTimeList.put("foreach循环", aForeach);
List<Long> aStream = diffLoopTimeList.getOrDefault("stream流", new ArrayList<>(20));
aStream.add(t4 - t3);
diffLoopTimeList.put("stream流", aStream);
List<Long> aParallelStream = diffLoopTimeList.getOrDefault("parallelStream流", new ArrayList<>(20));
aParallelStream.add(t5 - t4);
diffLoopTimeList.put("parallelStream流", aParallelStream);
}
}
测试过程和结果
测试一
20个元素的数组用4种方式遍历100w次
测试main方法:
结果:
for循环 : [17]ms
stream流 : [68]ms
foreach循环 : [35]ms
parallelStream流 : [16633]ms
初步结论:
数组数量较小时,for循环性能最优,foreach循环次之,stream流稍微落后于另外两种方式,并行流的性能明显不如另外几种方式。
测试二
去掉并行流在测试另外三种方式,100w次遍历测试110次去掉最高和最低的五次。
测试main方法:
结果:
for循环 : 727ms
stream流 : 1810ms
foreach循环 : 894ms
结论:for循环和foreach循环遍历少量元素的list时性能优于流处理。
测试三
遍历1000w数据100次,对比性能。
测试main方法:
结果:
for循环 : [2590]ms
stream流 : [2197]ms
foreach循环 : [2874]ms
parallelStream流 : [662]ms
结论:
数据量较大时,并行流效率远大于另外几种方式。