ConcurrentModificationException与多线程安全的关系

项目中开发用到ArrayList时,产生一些问题。  记录一些自己的理解,加深印象,当然网上也有其它的源码分析的资料

1、单线程下ArrayList获取跌代器iterator后,能不能再修改ArrayList的长度,如调用add、remove?

2、单线程下在iterator循环中增加、删除元素,如何操作?

3、多线程下使用ArrayList.iterator时也会抛出 ConcurrentModificationException异常 吗?

4、ConcurrentModificationException和 多线程安全 是什么关系? 是否解决了 多线程安全 后 就不会抛出 ConcurrentModificationException异常


结论:

1、单线程下ArrayList获取跌代器iterator后,是不能再修改ArrayList的长度的,如调用add、remove的。否则 会抛出运行时异常 ConcurrentModificationException,  从字面意义上理解就是 Concurrent:并发,Modification:修改, 即 并发修改异常。  但是我们这是在单线程环境下,哪儿来的 并发呢?   这里,我认为 java设计之初的理念上, Concurrent 不能仅仅理解为多线程,理解为并发是合理,并发即同时发生,在遍历的同时又发生了增删等操作。

单线程下创建跌代器: Iterator iterator = ArrayList.iterator(); 这个 Iterator 实质是 ArrayList 的 非静态内部类,在创建之初 便赋值为 ArrayList的 长度, 在之后 的iterator 的每一步操作时,都会检验 记录下的数组长度与 这个iterator所代表的ArrayList的长度 是否相等, 若相等则正常执行;若不相等,则会抛出ConcurrentModificationException;   

为什么会有这样的设计呢?

设计者认为 一个跌代器作为 ArrayList的 操作者,那它 应该能通过 跌代 来 操作完整的ArrayList 数据,当外界ArrayLit发生改变,而又无法通知到 Iterator时,这时将会引发很多不可确定性,给语言的使用者、使用目的 带来困扰。  因此设计者仅仅是通过抛出一个 运行时异常,来 禁止开发者这样调用。这样至少保证了程序的功能没有问题。




2、单线程下在iterator循环中删除元素,必须调用 iterator.remove、add,而不能调用 ArrayList.remove、add;否则iterator将抛出ConcurrentModificationException.

3、既然单线程下 修改iterator所指代的 List的长度后,都会抛出 并发修改异常, 更何况多线程。  例如,线程1 里 创建一个 ArrayList的 iterator,它正在遍历时,  线程2 往这个ArrayList里add、remove等操作,导致修改了这个ArrayList的长度, 那么线程1的 iterator 在执行时也会  判定长度发生变化,而抛出ConcurrentModificationException.


4、ConcurrentModificationException 和 多线程安全 并没有直接的关系。   首先我们举例来看看,什么是“多线程安全问题”.

例子:

下图是一段  售票的代码, 假如现在有多个 售票窗口, 即 多线程售票,  每个线程开始售票时,都会在 “代码1”处判断是否有余票,若有余票则进入出售。


但多线程的场景下,每个线程的代码可能在任意位置发生中断,切换到另外一个线程。 假如在只省最后一张票的情况下, 线程 通过了 代码1 处的判断,执行到代码2 处时, 线程1 因 时间片切换 而进入 等待状态,  这时切换到 线程2 售票,线程2 num=1,通过判断并成功出售一张票,并把剩余票数--为0;这时 时间片再切换到线程1,这时实际最后一张票已经被线程2出售掉了, 线程1继续执行售票的动作,并将剩余票数--为-1;   如果这样的系统运行在火车站的自动售票机上,就会出现通过机器卖了1001张票,而实质只有1000张票, 将有一个成功购票的人拿不到票而没有座位。这在业务上是绝对不允许的。

结论4:

a、多线程安全 指的是 多线程在操作同一个对象时,不会互相干扰; 并不是说  某个类存在 多线程安全问题,就会抛出ConcurrentModificationException异常。  

b、即使解决了多线程安全问题,也还是有可能抛出ConcurrentModificationException;  即使解决了 ConcurrentModificationException异常,也可能存在多线程安全问题;  这两者并不等价;

c、多线程安全问题 并不会 抛出运行时异常 而终止运行。   它只会在 很小的概率下出现,但这种小概率 在 大量用户、多次运行 时 就一定会出现 ,而一旦出现这种问题,将对业务系统造成  重大损失。

d、至于如何解决 多线程安全 问题 就不在这篇文章的讲解范围了,大致的方法如 synchronized 锁代码块,锁方法,锁静态方法,锁类 等等,具体细节有空再写一篇博客来促进自己的理解.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值