• ArrayList为什么是线程不安全的


    首先需要了解什么是线程安全:线程安全就是说多线程访问同一代码(对象、变量等),不会产生不确定的结果。 既然说ArrayList是线程不安全的,那么在多线程中操作一个ArrayList对象,则会出现不确定的结果。具体是怎样不确定,请看测试下面这段代码(在此测试ArrayList的add方法):

    public class ArrayListInThread implements Runnable{

    //线程不安全
    private List threadList = new ArrayList();
    //线程安全
    //private List threadList = Collections.synchronizedList(new ArrayList());

    @Override
    public void run() {
    try {
    Thread.sleep(10);
    }catch (InterruptedException e){
    e.printStackTrace();
    }
    //把当前线程名称加入list中
    threadList.add(Thread.currentThread().getName());
    }

    public static void main(String[] args) throws InterruptedException{
    ArrayListInThread listThread = new ArrayListInThread();


    for(int i = 0; i < 100; i++){
    Thread thread = new Thread(listThread, String.valueOf(i));
    thread.start();
    }

    //等待子线程执行完
    Thread.sleep(2000);

    System.out.println(listThread.threadList.size());
    //输出list中的值
    for(int i = 0; i < listThread.threadList.size(); i++){
    if(listThread.threadList.get(i) == null){
    System.out.println();;
    }
    System.out.print(listThread.threadList.get(i) + " ");
    }
    }
    }
    执行几次会发现结果不一样,甚至有时会出现ArrayIndexOutOfBoundsException,贴出几次执行的结果:

    结果一:

    结果二:

    结果三:

    以上执行结果说明ArrayList确实是线程不安全的,然后我们从线程并发的角度分析,为何会出现这样的结果:

    首先,我们先来看一下ArrayList中的add方法是如何实现的


    //添加元素e
    public boolean add(E e) {
    // 确定ArrayList的容量大小
    ensureCapacity(size + 1); // Increments modCount!!
    // 添加e到ArrayList中
    elementData[size++] = e;
    return true;
    }

    // 确定ArrarList的容量。
    // 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”
    public void ensureCapacity(int minCapacity) {
    // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的
    modCount++;
    int oldCapacity = elementData.length;
    // 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
    if (minCapacity > oldCapacity) {
    Object oldData[] = elementData;
    int newCapacity = (oldCapacity * 3)/2 + 1;
    //如果还不够,则直接将minCapacity设置为当前容量
    if (newCapacity < minCapacity)
    newCapacity = minCapacity;
    elementData = Arrays.copyOf(elementData, newCapacity);
    }
    }

    结果中,有的值没有出现(结果一中3没有出现),有的出现了null值,这是由于赋值时出现了覆盖。赋值语句为:elementData[size++] = e,这条语句可拆分为两条:
    1. elementData[size] = e;
    2. size ++;
    假设A线程执行完第一条语句时,CPU暂停执行A线程转而去执行B线程,此时ArrayList的size并没有加一,这时在ArrayList中B线程就会覆盖掉A线程赋的值,而此时,A线程和B线程先后执行size++,便会出现值为null的情况;至于结果三中出现的ArrayIndexOutOfBoundsException异常,
    则是A线程在执行ensureCapacity(size+1)后没有继续执行,此时恰好minCapacity等于oldCapacity,B线程再去执行,同样由于minCapacity等于oldCapacity,ArrayList并没有增加长度,B线程可以继续执行赋值(elementData[size] = e)并size ++也执行了,此时,CPU又去执行A线程的赋值操作,由于size值加了1,size值大于了ArrayList的最大长度,
    因此便出现了ArrayIndexOutOfBoundsException异常。

    既然ArrayList是线程不安全的,但如果需要在多线程中使用,可以采用list<Object> list =Collections.synchronizedList(new ArrayList<Object>)来创建一个ArrayList对象。

    原文:https://blog.csdn.net/zhangxin961304090/article/details/46804065

  • 相关阅读:
    挑战编程 uva100 3n+1
    《算法问题实战策略》 BOGGLE
    图论 最短路专辑
    acwing 76. 和为S的连续正数序列
    leetcode 19 删除链表的倒数第N个节点
    水文一篇 汇报下最*的学**况
    acwing 81. 扑克牌的顺子
    Solr基础理论与维护管理快速上手(含查询参数说明)
    Solr基础理论与维护管理快速上手(含查询参数说明)
    利用SolrJ操作solr API完成index操作
  • 原文地址:https://www.cnblogs.com/panbingqi/p/11041182.html
Copyright © 2020-2023  润新知