`
zy116494718
  • 浏览: 470662 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ArrayList 和 CopyOnWriteArrayList 线程安全测试

    博客分类:
  • Java
 
阅读更多

ArrayList 是 非线程安全的, CopyOnWriteArrayList 是一个线程安全,并且在读操作时无锁的ArrayList,且适合并发访问。对于集合元素数为10000,线程数量为100的情况下进行性能测试,随着元素数量和线程数量的增加,CopyOnWriteArrayList在增加元素和删除元素时的性能下降非常明显,并且性能会比ArrayList低。但在查找元素这点上随着线程数的增长,性能较ArrayList会好很多。

 

故在读多写少的并发场景中,CopyOnWriteArrayList较之ArrayList是更好的选择。

 

 

下面对两种方式的线程安全进行下测试:

 

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class ThreadSafeDemo {
    public static int demo(final List list, final int testCount) throws InterruptedException {
        ThreadGroup group = new ThreadGroup(list.getClass().getName() + "@" + list.hashCode()); 
        final Random rand = new Random(); 
        
        Runnable listAppender = new Runnable() {  // 这里面实现了Runnable接口类,覆盖了它的run方法
            public void run() {
                try {
                    Thread.sleep(rand.nextInt(2));
                } catch (InterruptedException e) {
                    return; 
                } 
                list.add("0"); 
            }
        }; 
        
        for (int i = 0; i < testCount; i++) {
            new Thread(group, listAppender, "InsertList-" + i).start(); 
                             //java.lang.Thread
.Thread(ThreadGroup
 group, Runnable
 target, String
 name)
        
      }
        
        while (group.activeCount() > 0) {
            Thread.sleep(10); 
        }
        
        return list.size(); 
    }
    public static void main(String[] args) throws InterruptedException {
        List unsafeList = new ArrayList(); 
        List safeList = Collections.synchronizedList(new ArrayList()); // 也可以换成new CopyToWriteArrayList
        final int N = 10000; 
        for (int i = 0; i < 10; i++) {
            unsafeList.clear(); 
            safeList.clear(); 
            int unsafeSize = demo(unsafeList, N); 
            int safeSize = demo(safeList, N); 
            System.out.println("unsafe/safe: " + unsafeSize + "/" + safeSize); 
        }
    }
}

 

测试的结果为:

unsafe/safe: 9992/10000
unsafe/safe: 9996/10000
unsafe/safe: 9990/10000
unsafe/safe: 9992/10000
unsafe/safe: 9997/10000
unsafe/safe: 9997/10000
unsafe/safe: 9993/10000
unsafe/safe: 9995/10000
unsafe/safe: 9993/10000
unsafe/safe: 9995/10000

 

之所以会造成不安全线程list数不足10000,主要有两点:

首先我们来看ArrayList的源码:

 

public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

 

主要问题出在size++这块,因为该方法不是线程安全的,所以就有可能出现以下两种情况:

1)线程A和线程B同样取得size=10,然后在相同位置10插入了两遍值,然后在都执行size++,结果size变成了12,这样下次再有线程进来时会在12的位置继续插入值,而11则变成了null,实验下果然如此,但是其实这并不能解释为什么list1.size的值会减少,只能解释为什么list中有的值为null

2) size++这个操作同样不是线程安全的,它分成两个步骤,第一,取size的位置,第二,size位置+1,这样就有可能A线程和B线程同时取到size的位置,然后+1,这样A,B线程执行完size++后,size的值为11而不是12,所以就会有不同的线程同时在一个位置赋值,导致list的数量不足。

 

 

 

 

分享到:
评论

相关推荐

    Java集合教程吐血整理干货.md

    HashMap是线程不安全的,并允许null key 和 null value。 HashMap在我当前的jdk版本(11)的默认容量为0,在第一次添加元素的时候才初始化容量为 16, 之后才扩容为原来的2倍。 HashMap的扩容是根据 threshold决定的 : ...

    java集合-CopyOnWriteArrayList的使用

    在Java中,CopyOnWriteArrayList(写入时复制数组列表)是线程安全的集合类,它实现了List接口,并使用了"写入时复制"的策略来保证线程安全性。 CopyOnWriteArrayList的主要特点是:在进行修改操作(例如添加、修改...

    java集合类原理面试题

    线程安全和线程不安全的分别有哪些? Map接口有哪些实现类? 描述一下Map put的过程 如何得到一个线程安全的Map? HashMap有什么特点? ConcurrentHashMap是怎么分段分组的? ConcurrentHashMap是怎么分段分组的? ...

    javabiginteger源码-MultiThreadMode:多线程模式

    java biginteger 源码 MultiThreadMode Single Thread Execution模式 使用synchronized方法或代码块,只能保证某一段代码是只能由一个线程执行。...CopyOnWriteArrayList线程安全的类,适用于读操作频繁的场景。 Gua

    CopyOnWriteArrayList是怎么实现写有锁,读无锁,读写之间不堵塞的?(加强版读写分离源码剖析)

    CopyOnWriteArrayList是ArrayList的线程安全版本,从名字推测,CopyOnWriteArrayList是在有写操作的时候会copy一份数据,然后写完再设置成新的数据。CopyOnWriteArrayList适用于读多写少的并发场景。而...

    Java的CopyOnWriteArrayList功能详解,及无法保证数据是实时同步.docx

    高并发的情况下,一般都要求性能要给力,Vector 显然不够格,所以被遗忘在角落也是“罪有应得”啊。...那有些同学可能会说,可以使用 Collections.synchronizedList() 让 ArrayList 变成线程安全啊。

    List效率的比较

     4.CopyOnWriteArrayList 因为线程安全的原因,致使性能降低很多,所以慎用;  5.Vector 没有传说中那么低的效率;  6.让Stack 来做List 的事可以,不过语义上Stack 不应该做过多的List 的事情;  7.在排序中,...

    Java 高频面试题:聊一聊 JUC 下的 CopyOnWriteArrayList

    ArrayList 是我们常用的工具类之一,但是在多线程的情况下,ArrayList 作为共享变量时,并不是线程安全的。主要有以下两个原因: 1、ArrayList 自身的 elementData、size、modCount 在进行操作的时候,都没有加锁 ...

    Java容器.xmind

    底层哈希表,基于hashCode的equals的比较方式,线程不安全,存取速度快。 SortedSet 标记: interface TreeSet 标记: class 实现comparable接口,元素是以二叉树的形式存放的。线程不安全 CopyOnWriteArraySet 标记:...

    Java并发包讲解

    ## 线程安全-并发容器JUC--原理以及分析 1.arrayList --copyonWriteArraylist 优缺点 2.HashSet,TreeSet -- CopyONWriteArraySet,ConcurrentSkipListSet 3.hashMap , treeMap -- ConcurrentHashMap,...

    leetcode题库-JavaInterview:关于采访和书籍的注意事项

    线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。 运行时数据区域、垃圾收集、类加载。 JavaIO知识,字符流,字节流,Socket,NIO。 操作系统 网络 面向对象 Gof 的 23 种设计模式。 ...

    基于javatcpsocket通信的拆包和装包源码-all-in-one:知识点总结

    基于java tcp socket通信的拆包和装包源码 基础 集合 List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问,查找元素效率...1、Vector是线程同步的,所以它也是线程安全的,而ArrayLi

    【Java】常用数据集合体系和特点(汇总)

    Collection体系集合1.1 List 表① ArrayList 类(数组)② Vector 类(数组、线程同步)③ LinkedList 类(链表)④ CopyOnWriteArrayList 类(线程安全且高效的List)1.2 Set 集合① HashSet 类(HashCode)② ...

Global site tag (gtag.js) - Google Analytics