ArrayList线程不安全详解

原创 2015年07月08日 15:33:19

首先需要了解什么是线程安全:线程安全就是说多线程访问同一代码(对象、变量等),不会产生不确定的结果。 既然说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对象。

版权声明:本文为原创文章,转载请注明出处。

为什么说ArrayList是线程不安全的?

首先说一下什么是线程不安全:线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。...
  • jiaochunyu1992
  • jiaochunyu1992
  • 2016年04月18日 09:51
  • 12325

解决ArrayList线程不安全

前些天做项目时,程序出现意外的问题,经后来分析是使用ArrayList这个线程不安全的方法导致 解决这个问题通常有两种方法(个人认为) 一:使用synchronized关键字,这个大家应该都很熟悉...
  • sdefzhpk
  • sdefzhpk
  • 2012年03月01日 19:29
  • 27008

为什么说ArrayList是线程不安全的?

一.概述 对于ArrayList,相信大家并不陌生。这个类是我们平时接触得最多的一个列表集合类。 面试时相信面试官首先就会问到关于它的知识。一个经常被问到的问题就是:ArrayList是否是线程安...
  • u012859681
  • u012859681
  • 2017年10月11日 17:52
  • 362

ArrayList线程不安全分析

分析ArrayList的线程不安全因素,不对之处欢迎大家指正
  • u013769320
  • u013769320
  • 2015年06月01日 10:02
  • 1820

为什么说ArrayList是线程不安全的?

一个 ArrayList ,在添加一个元素的时候,它可能会有两步来完成: 1. 在 Items[Size] 的位置存放此元素; 2. 增大 Size 的值。   在单线程运行的情况下,如果 Si...
  • varyall
  • varyall
  • 2016年12月18日 23:39
  • 809

在JAVA中ArrayList如何保证线程安全

保证线程安全的三种方法: 不要跨线程访问共享变量 使共享变量是final类型的 将共享变量的操作加上同步 一开始就将类设计成线程安全的, 比在后期重新修复它,更容易. 编写多线程程序, 首先保证它...
  • ApatheCrazyFan
  • ApatheCrazyFan
  • 2016年11月03日 11:17
  • 5788

如何使ArrayList线程安全

List list = Collections.synchronizedList(new ArrayList());
  • wanzhix
  • wanzhix
  • 2017年03月13日 20:22
  • 650

关于ArrayList的涉及线程安全问题

1.简介 ArrayList的基本使用和介绍 2.介绍 ArrayList的底层是数组,所以决定了他查询快,增删慢的特点,但是他的效率高,线程不安全; 3.解决办法: 虽然ArrayList线程不安全...
  • w2232097312
  • w2232097312
  • 2016年08月11日 12:19
  • 1964

java 多线程同时操作ArrayList 出现ConcurrentModificationException 解决办法

尊重原创,原文转载地址:http://www.2cto.com/kf/201403/286536.html#SOHUCS     一、单线程 1. 异常情况举例 只要抛出出现异常,可以肯定的...
  • u014746965
  • u014746965
  • 2015年12月25日 17:14
  • 4693

ArrayList线程安全

今天面试 有个 问题,如何把 ArrayList进行线程同步? arraylist经常用,不是
  • zlj_fly
  • zlj_fly
  • 2014年10月28日 19:04
  • 3753
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ArrayList线程不安全详解
举报原因:
原因补充:

(最多只允许输入30个字)