ArrayList线程不安全详解
2015-07-08 15:33
260 查看
首先需要了解什么是线程安全:线程安全就是说多线程访问同一代码(对象、变量等),不会产生不确定的结果。 既然说ArrayList是线程不安全的,那么在多线程中操作一个ArrayList对象,则会出现不确定的结果。具体是怎样不确定,请看测试下面这段代码(在此测试ArrayList的add方法):
执行几次会发现结果不一样,甚至有时会出现ArrayIndexOutOfBoundsException,贴出几次执行的结果:
结果一:
![](http://img.blog.csdn.net/20150708155606857?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
结果二:
![](http://img.blog.csdn.net/20150708155638200?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
结果三:
![](http://img.blog.csdn.net/20150708155709741?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
以上执行结果说明ArrayList确实是线程不安全的,然后我们从线程并发的角度分析,为何会出现这样的结果:
首先,我们先来看一下ArrayList中的add方法是如何实现的(查看详细源码请点击):
结果中,有的值没有出现(结果一中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对象。
执行几次会发现结果不一样,甚至有时会出现ArrayIndexOutOfBoundsException,贴出几次执行的结果:
结果一:
结果二:
结果三:
以上执行结果说明ArrayList确实是线程不安全的,然后我们从线程并发的角度分析,为何会出现这样的结果:
首先,我们先来看一下ArrayList中的add方法是如何实现的(查看详细源码请点击):
结果中,有的值没有出现(结果一中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对象。
相关文章推荐
- 详细探究Spark的shuffle实现
- 堆和栈的区别(转过无数次的文章)
- 简述UIDatePicker的用法
- C++ 开源库
- Android 的OpenGL ES与EGL
- java多线程下载文件
- openoffice转换过程中遇到繁体字文档转换失败的问题
- 等待进程结束函数中的BUG
- iOS线程开发小结
- Capturing ASP.NET Application Startup Exceptions
- ORA-14452的出现原因解析及解决方法(转)
- 省队集训day6 B
- openoffice转换过程中遇到繁体字文档转换失败的问题
- ASP.NET - 用户控件制作
- javaEE开发中使用session同步和token机制来防止并发重复提交
- Java toString equals hashCode 方法的重写
- 简述文本属性Attributes的用法
- eclipse安装C++工程环境----CDT环境————eclipse开发openCV环境准备2
- Activity调用dispatchTouchEvent()和onTouchEvent()方法
- GO语言使用开源SSH模拟终端