List的同步类比较

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)、顺序读取和随机读取,各十轮。据此编写代码。代码太长了,所以放到最后

3,测试平台

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

4,测试结果

单位:毫秒

List的同步类比较

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

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

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随机读取性能较好,顺序读取性能和写入性能较差。

附录 测试代码

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 lsA = new ArrayList<>();
        List lsV = new Vector<>();
        List lsS = Collections.synchronizedList(new ArrayList<>());
        List 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 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 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 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 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 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 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);
    }
}

Original: https://www.cnblogs.com/CounterX/p/16400925.html
Author: 计数寄存器
Title: List的同步类比较

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/713839/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球