CopyOnWriteArrayList和SynchronizedList的执行效率差别

CopyOnWriteArrayList和SynchronizedList这两者循环插入数据时,执行效率都有不利的地方,CopyOnWriteArrayList是每次都要弄个快照,添加完,把快照数据给主数据,再废掉快照,SynchronizedList则是到处加锁,加锁,就需要解锁。

今天闲来无事,自己写个demo来做测试,循环加一百万个数字。JDK版本1.8。
  1. Instant begin = Instant.now();
  2. long beginLong = begin.toEpochMilli();
  3. Collections.synchronizedList(new ArrayList<>(1048576));
  4. for(int i= 0; i<1_000_000; i++) {
  5. list.add(i);
  6. }
  7. Instant end = Instant.now();
  8. long endLong = end.toEpochMilli();
  9. System.out.println((endLong - beginLong));
使用SynchronizedList,执行时间:54ms
再用CopyOnWriteArrayList试试看
  1. Instant begin = Instant.now();
  2. long beginLong = begin.toEpochMilli();
  3. List<Integer> list = new CopyOnWriteArrayList<>(new ArrayList<>(1048576));
  4. for(int i= 0; i<1_000_000; i++) {
  5. list.add(i);
  6. }
  7. Instant end = Instant.now();
  8. long endLong = end.toEpochMilli();
  9. System.out.println((endLong - beginLong));
执行时间:598375ms,接近10分钟了。差距将近1000倍
再用CopyOnWriteArrayList的addAll试试看
  1. Instant begin = Instant.now();
  2. long beginLong = begin.toEpochMilli();
  3. List<Integer> list = Collections.synchronizedList(new ArrayList<>(1048576));
  4. for(int i= 0; i<1_000_000; i++) {
  5. list.add(i);
  6. }
  7. Instant end = Instant.now();
  8. long endLong = end.toEpochMilli();
  9. List<Integer> abcd = new CopyOnWriteArrayList<>();
  10. abcd.addAll(list);
  11. Instant end1 = Instant.now();
  12. long endLong1 = end1.toEpochMilli();
  13. System.out.println((endLong - beginLong));
  14. System.out.println((endLong1 - endLong));
执行结果:3ms。
  1. List<Integer> abcd = new CopyOnWriteArrayList<>(list);
直接将一个List作为初始化时的参数的执行时间也差不多是2ms-3ms。
所以,如果要循环插入大量信息,SynchronizedList的效率较高,CopyOnWriteArrayList基本可以放弃。但如果前面已经有获得的List数据,以addAll的方式或者使用构造方法一次性批量加入CopyOnWriteArrayList,这个效率还是很高的。