我们都知道,ArrayList 天生就不是线程安全的,但是很多人也就是道听途说而已。并没有实际的进行测试,也并不清楚 ArrayList 为什么不是线程安全的!

这不,昨天还有人问我为什么?说面试官让他写一个 bug。答案其实很简单,今天我们就一起来动手写一个“bug”!

看下面这个测试代码:

线程 MyThread 代码如下所示:

多次执行后,运行结果有两种。一种就是常见的 java.lang.ArrayIndexOutOfBoundsException 异常。

还有一种就是跑成功了,但是数据不对。甚至时不时会抛出个 IndexOutOfBoundsException 异常,这种情况很少见,多数情况下,都是直接抛出异常。

观察上面的代码,其实很简单,就是多线程,向 list 中 add 元素。但是,最终结果却和预期不一致。为什么会漏掉数据呢?

这是因为 List 对象,在做 add 时,执行 Arrays.copyOf 的时候,返回一个新的数组对象。当有线程 t1、t2、... 同时进入 grow方法,多个线程都会执行 Arrays.copyOf 方法,返回多个不同的 elementData 对象,假如,t1 先返回,t2 后返回,那么 List.elementData == t1.elementData,然后 t2 也返回后,这时 List.elementData == t2.elementData,所以,t2.elementData 就把 t1.elementData 数据给覆盖了。导致 t1.elementData 被丢失。

那么这种问题,怎么解决呢?

一种是使用 Vector,还有一种是使用 Collections.synchronizedList(new ArrayList()) 。但是你也要注意符合操作!

这就是,面试中,让我写一个“bug”,并修复一个“bug”。