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,测试结果

单位:毫秒

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<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);
}
}

List的同步类比较的更多相关文章

  1. Java中多线程同步类 CountDownLatch

    在多线程开发中,常常遇到希望一组线程完成之后在执行之后的操作,java提供了一个多线程同步辅助类,可以完成此类需求: 类中常见的方法: 其中构造方法:CountDownLatch(int count) ...

  2. 16.同步类容器Collections.synchronized

    voctor动态数组.同步类容器,底层实现基于:Collections.synchronized package demo5; import java.util.ArrayList; import j ...

  3. 15.同步类容器Vector

    同步类容器1 1.线程都是安全的. 2.在某些场景下需要加锁来保护“复合操作” a.迭代:反复去访问元素.遍历完容器所有的元素 b.跳转:根据下标制定去访问查找元素 c.条件运算 3.复合操作在多线程 ...

  4. Java线程同步类容器和并发容器(四)

    同步类容器都是线程安全的,在某些场景下,需要枷锁保护符合操作,最经典ConcurrentModifiicationException,原因是当容器迭代的过程中,被并发的修改了内容. for (Iter ...

  5. 同步类容器和并发类容器——ConcurrentMap、CopyOnWrite、Queue

     一 同步类容器同步类容器都是线程安全的,但在某些场景中可能需要加锁来保证复合操作. 符合操作如:迭代(反复访问元素,遍历完容器中所有元素).跳转(根据指定的顺序找到当前元素的下一个元素).条件运算. ...

  6. Java多线程信号量同步类CountDownLatch与Semaphore

    信号量同步是指在不同线程之间,通过传递同步信号量来协调线程执行的先后次序.CountDownLatch是基于时间维度的Semaphore则是基于信号维度的. 1:基于执行时间的同步类CountDown ...

  7. 同步类的基础AbstractQueuedSynchronizer(AQS)

    同步类的基础AbstractQueuedSynchronizer(AQS) 我们之前介绍了很多同步类,比如ReentrantLock,Semaphore, CountDownLatch, Reentr ...

  8. 解读java同步类CountDownLatch

    同步辅助类: CountDownLatch是一个同步辅助类,在jdk5中引入,它允许一个或多个线程等待其他线程操作完成之后才执行. 实现原理 : CountDownLatch是通过计数器的方式来实现, ...

  9. synchronized 线程同步-类级别锁定

    1.demo 说明:代码中通过 printNum 方法传入参数判断 a.b 分别对 num 这个参数的值进行了修改. package demo1; import sun.applet.Main; pu ...

随机推荐

  1. Java线程池ThreadPoolExecutor极简教程

    ThreadPoolExecutor 简介 ThreadPoolExecutor 是 java.util.concurrent 包下的一个类,在jdk1.5版本引入,帮助开发人员管理线程并方便地执行并 ...

  2. 对抗噪音,一键清晰,HMS Core音频编辑服务给你“录音棚”般的体验

    短视频时代来临,一部手机就可以玩转多种花样,所以越来越多的自由创作者加入这个行业,平时生活中用手机拍短视频.街头唱歌的非专业从业者随处可见.离开了录音棚,没有专业.统一的录音设备,无论在家里还是在路边 ...

  3. Redis概述及基本数据结构

    SQL vs NoSQL 结构化 SQL 是结构化的,一旦定义了表结构,以后在维护数据的时候必须严格遵守定义的结构. NoSQL 是非结构化的,常见的形式有 Redis 的 Key-Value 存储形 ...

  4. (干货)基于 veImageX 搭建海报生成平台 -- 附源码

    前言 618 年中促销即将来临,很多公司都会通过海报来宣传自己的促销方案,通常情况下海报由设计团队基于 PS.Sketch 等工具创作,后期若想替换海报文案.商品列表等内容则需打开原工程进行二次创作, ...

  5. 在 4GB 物理内存的机器上,申请 8G 内存会怎么样?

    作者:小林coding 计算机八股文刷题网站:https://xiaolincoding.com/ 大家好,我是小林. 看到读者在群里讨论这些面试题: 其中,第一个问题「在 4GB 物理内存的机器上, ...

  6. css设置元素背景透明度的2种方式

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月9日. 设置元素的背景的透明度可以使用2种方式:方式1:opacity属性.方式2:使用rgba值.两种方式有一点差异,opaci ...

  7. 关于个人项目(臻美MV【仿抖音App】)滑动切换视频的分析(前端角度)

    我们知道你天天刷抖音的时候可以上滑切换视频,互不影响.那么我们站在前端的角度能否可以实现这种效果呢?这是我的个人项目:臻美MV 下面我是用Vue写的,现在我把它开源. Vue: 初始界面 <te ...

  8. NC212914 牛牛与后缀表达式

    NC212914 牛牛与后缀表达式 题目 题目描述 给定牛牛一个后缀表达式 \(s\) ,计算它的结果,例如,1+1对应的后缀表达式为1#1#+,'#'作为操作数的结束符号. 其中,表达式中只含有'+ ...

  9. CF1656E Equal Tree Sums 题解

    题目链接 思路分析 自认为是一道很好的构造题,但是我并不会做. 看了题解后有一些理解,在这里再梳理一遍巧妙的思路. 我们先来看这样的一张图: 我们发现当去掉叶子节点的父亲时,剩下树的价值和等于叶子节点 ...

  10. 微信小程序接口请求/form-data/单文件、多文件上传

    1.普通的微信请求封装 1 const http = (options) =>{ 2 return new Promise((resolve,reject) => { 3 wx.reque ...