如何将List的同步类比较转换为长尾词?

2026-04-18 03:452阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1348个文字,预计阅读时间需要6分钟。

如何将List的同步类比较转换为长尾词?

TL;DR: CopyOnWriteArrayList在多线程顺序读取上有优势,但随机读取性能较差,写入性能差异大。Vector顺序读取性能一般,随机读取性能较好。

TL;NRs
  • CopyOnWriteArrayList类在多线程顺序读取上有很大的优势,但在随机读取上反而有较大的劣势,且在写入方面性能极差。
  • Vector类在顺序读取方面性能较差,但在随机读取方面有较大的优势,写入方面性能也还可以。
1,引言

java线程安全的List实现有以下三种:

  1. new Vector<>()
  2. Collections.synchronizedList(new ArrayList<>())
  3. new CopyOnWriteArrayList<>()

通常认为使用了synchronized会导致运行变慢,那么在java针对synchronized进行一系列优化后,现在的情况如何呢?为了检验这一说法,写了一个验证程序进行验证。

2,验证代码

ArrayList作为基础,分别测试4种List的顺序写入(0 ~ 1 << 24)、顺序读取和随机读取,各十轮。据此编写代码如下

import java.util.*; import java.util.concurrent.*; public class VectorTest { private static final int CNT = 1 << 24; private static final Random rand = new Random(); public static void main(String[] args) throws InterruptedException { int writeRound = 10, readRound = 10, randomReadRound = 10; int nRead = 20, nRandomRead = 20; List<Integer> lsA = new ArrayList<>(); List<Integer> lsV = new Vector<>(); List<Integer> lsS = Collections.synchronizedList(new ArrayList<>()); List<Integer> lsC = new CopyOnWriteArrayList<>(); test(lsA, "ArrayList", writeRound, readRound, randomReadRound); test(lsV, "Vector", writeRound, readRound, randomReadRound); test(lsS, "SynArrayList", writeRound, readRound, randomReadRound); lsC.addAll(lsA); test(lsC, "COWList", 0, readRound, randomReadRound); multiThreadTest(lsV, "Vector", nRead, nRandomRead); multiThreadTest(lsS, "SynArrayList", nRead, nRandomRead); multiThreadTest(lsC, "COWList", nRead, nRandomRead); } private static void test(List<Integer> list, String name, int writeRound, int readRound, int randomReadRound) { int max = 0, min = Integer.MAX_VALUE, sum = 0; int[] w = new int[writeRound], r = new int[readRound], rr = new int[randomReadRound]; for (int i = 0; i < writeRound; i++) { list.clear(); int v = w[i] = writeTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s write test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : w) System.out.printf("%d\t", v); System.out.println(); sum = max = 0; min = Integer.MAX_VALUE; for (int i = 0; i < readRound; i++) { int v = r[i] = readTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s read test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : r) System.out.printf("%d\t", v); System.out.println(); sum = max = 0; min = Integer.MAX_VALUE; for (int i = 0; i < randomReadRound; i++) { int v = rr[i] = randomReadTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s random read test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : rr) System.out.printf("%d\t", v); System.out.println(); } private static int writeTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.add(i); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static int readTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.get(i); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static int randomReadTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.get(rand.nextInt(CNT)); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static List<Integer> ls; private static long t2 = 0; private static CountDownLatch cdl; public static class ThreadRead extends Thread { public void run() { for (int i = 0; i < CNT; i++) ls.get(i); long t1 = System.currentTimeMillis(); t2 = Math.max(t1, t2); cdl.countDown(); } } public static class ThreadRandomRead extends Thread { public void run() { for (int i = 0; i < CNT; i++) ls.get(rand.nextInt(CNT)); long t1 = System.currentTimeMillis(); t2 = Math.max(t1, t2); cdl.countDown(); } } private static void multiThreadTest(List<Integer> list, String name, int nRead, int nRandomRead) throws InterruptedException { int tr = 0, trr = 0; ls = list; cdl = new CountDownLatch(nRead); long t0 = System.currentTimeMillis(); for (int i = 0; i < nRead; i++) { new ThreadRead().start(); } cdl.await(); tr = (int)(t2 - t0); cdl = new CountDownLatch(nRandomRead); t2 = 0; t0 = System.currentTimeMillis(); for (int i = 0; i < nRandomRead; i++) { new ThreadRandomRead().start(); } cdl.await(); trr = (int)(t2 - t0); System.out.printf("%s: tr = %d, trr = %d\n", name, tr, trr); } } 3,测试平台

垃圾笔记本,使用Intel酷睿i5 7200U
java版本为java 12,HotSpot虚拟机

4,测试结果

单位:毫秒

5,结果分析

ArrayList(A)、Vector(V)、Collections.synchronizedList(new ArrayList<>())(S)、以及CopyOnWriteArrayList(C)四种类型的结果分别如下
十轮写入,单位毫秒

A V S C 总时间 6426 9365 10186 inf 最大时间 1313 1016 1096 inf 最小时间 239 815 672 inf

十轮单线程顺序读,单位毫秒

如何将List的同步类比较转换为长尾词?

A V S C 总时间 41 2247 1538 1560 最大时间 22 418 200 167 最小时间 0 196 129 148

十轮单线程随机读,单位毫秒

A V S C 总时间 2167 4908 11792 11133 最大时间 256 573 1372 1264 最小时间 202 473 1110 1030

十线程顺序读,单位毫秒

V S C 总时间 11232 12650 696

十线程随机读,单位毫秒

V S C 总时间 16828 17888 26089 6,结论

单线程写入性能:A > V = S >>>> C
单线程顺序读取性能:A >> S = C > V
单线程随机读取性能:A > V > S = C
20线程顺序读取性能:C >> V > S
20线程随机读取性能:V > S >> C
COW顺序读取性能较好,随机读取性能较差,写入性能极差。
Vector随机读取性能较好,顺序读取性能和写入性能较差。

本文共计1348个文字,预计阅读时间需要6分钟。

如何将List的同步类比较转换为长尾词?

TL;DR: CopyOnWriteArrayList在多线程顺序读取上有优势,但随机读取性能较差,写入性能差异大。Vector顺序读取性能一般,随机读取性能较好。

TL;NRs
  • CopyOnWriteArrayList类在多线程顺序读取上有很大的优势,但在随机读取上反而有较大的劣势,且在写入方面性能极差。
  • Vector类在顺序读取方面性能较差,但在随机读取方面有较大的优势,写入方面性能也还可以。
1,引言

java线程安全的List实现有以下三种:

  1. new Vector<>()
  2. Collections.synchronizedList(new ArrayList<>())
  3. new CopyOnWriteArrayList<>()

通常认为使用了synchronized会导致运行变慢,那么在java针对synchronized进行一系列优化后,现在的情况如何呢?为了检验这一说法,写了一个验证程序进行验证。

2,验证代码

ArrayList作为基础,分别测试4种List的顺序写入(0 ~ 1 << 24)、顺序读取和随机读取,各十轮。据此编写代码如下

import java.util.*; import java.util.concurrent.*; public class VectorTest { private static final int CNT = 1 << 24; private static final Random rand = new Random(); public static void main(String[] args) throws InterruptedException { int writeRound = 10, readRound = 10, randomReadRound = 10; int nRead = 20, nRandomRead = 20; List<Integer> lsA = new ArrayList<>(); List<Integer> lsV = new Vector<>(); List<Integer> lsS = Collections.synchronizedList(new ArrayList<>()); List<Integer> lsC = new CopyOnWriteArrayList<>(); test(lsA, "ArrayList", writeRound, readRound, randomReadRound); test(lsV, "Vector", writeRound, readRound, randomReadRound); test(lsS, "SynArrayList", writeRound, readRound, randomReadRound); lsC.addAll(lsA); test(lsC, "COWList", 0, readRound, randomReadRound); multiThreadTest(lsV, "Vector", nRead, nRandomRead); multiThreadTest(lsS, "SynArrayList", nRead, nRandomRead); multiThreadTest(lsC, "COWList", nRead, nRandomRead); } private static void test(List<Integer> list, String name, int writeRound, int readRound, int randomReadRound) { int max = 0, min = Integer.MAX_VALUE, sum = 0; int[] w = new int[writeRound], r = new int[readRound], rr = new int[randomReadRound]; for (int i = 0; i < writeRound; i++) { list.clear(); int v = w[i] = writeTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s write test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : w) System.out.printf("%d\t", v); System.out.println(); sum = max = 0; min = Integer.MAX_VALUE; for (int i = 0; i < readRound; i++) { int v = r[i] = readTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s read test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : r) System.out.printf("%d\t", v); System.out.println(); sum = max = 0; min = Integer.MAX_VALUE; for (int i = 0; i < randomReadRound; i++) { int v = rr[i] = randomReadTest(list); max = Math.max(max, v); min = Math.min(min, v); sum += v; } System.out.printf("%s random read test: sum = %d, max = %d, min = %d\n", name, sum, max, min); for (int v : rr) System.out.printf("%d\t", v); System.out.println(); } private static int writeTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.add(i); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static int readTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.get(i); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static int randomReadTest(List<Integer> list) { long t0 = System.currentTimeMillis(); for (int i = 0; i < CNT; i++) list.get(rand.nextInt(CNT)); long t1 = System.currentTimeMillis(); return (int)(t1 - t0); } private static List<Integer> ls; private static long t2 = 0; private static CountDownLatch cdl; public static class ThreadRead extends Thread { public void run() { for (int i = 0; i < CNT; i++) ls.get(i); long t1 = System.currentTimeMillis(); t2 = Math.max(t1, t2); cdl.countDown(); } } public static class ThreadRandomRead extends Thread { public void run() { for (int i = 0; i < CNT; i++) ls.get(rand.nextInt(CNT)); long t1 = System.currentTimeMillis(); t2 = Math.max(t1, t2); cdl.countDown(); } } private static void multiThreadTest(List<Integer> list, String name, int nRead, int nRandomRead) throws InterruptedException { int tr = 0, trr = 0; ls = list; cdl = new CountDownLatch(nRead); long t0 = System.currentTimeMillis(); for (int i = 0; i < nRead; i++) { new ThreadRead().start(); } cdl.await(); tr = (int)(t2 - t0); cdl = new CountDownLatch(nRandomRead); t2 = 0; t0 = System.currentTimeMillis(); for (int i = 0; i < nRandomRead; i++) { new ThreadRandomRead().start(); } cdl.await(); trr = (int)(t2 - t0); System.out.printf("%s: tr = %d, trr = %d\n", name, tr, trr); } } 3,测试平台

垃圾笔记本,使用Intel酷睿i5 7200U
java版本为java 12,HotSpot虚拟机

4,测试结果

单位:毫秒

5,结果分析

ArrayList(A)、Vector(V)、Collections.synchronizedList(new ArrayList<>())(S)、以及CopyOnWriteArrayList(C)四种类型的结果分别如下
十轮写入,单位毫秒

A V S C 总时间 6426 9365 10186 inf 最大时间 1313 1016 1096 inf 最小时间 239 815 672 inf

十轮单线程顺序读,单位毫秒

如何将List的同步类比较转换为长尾词?

A V S C 总时间 41 2247 1538 1560 最大时间 22 418 200 167 最小时间 0 196 129 148

十轮单线程随机读,单位毫秒

A V S C 总时间 2167 4908 11792 11133 最大时间 256 573 1372 1264 最小时间 202 473 1110 1030

十线程顺序读,单位毫秒

V S C 总时间 11232 12650 696

十线程随机读,单位毫秒

V S C 总时间 16828 17888 26089 6,结论

单线程写入性能:A > V = S >>>> C
单线程顺序读取性能:A >> S = C > V
单线程随机读取性能:A > V > S = C
20线程顺序读取性能:C >> V > S
20线程随机读取性能:V > S >> C
COW顺序读取性能较好,随机读取性能较差,写入性能极差。
Vector随机读取性能较好,顺序读取性能和写入性能较差。