面试题答案
一键面试复制过程实现
在Java的ArrayList
扩容时,原数组内容复制到新数组是通过System.arraycopy()
方法实现。ArrayList
的扩容机制如下:
- 当向
ArrayList
中添加元素,且当前数组已满(即size == elementData.length
)时,会触发扩容。 - 扩容时,新数组大小通常是原数组大小的1.5倍(
int newCapacity = oldCapacity + (oldCapacity >> 1);
)。 - 然后通过
System.arraycopy()
方法将原数组内容复制到新数组。其方法签名为public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);
,在ArrayList
中类似System.arraycopy(elementData, 0, newElementData, 0, Math.min(size, newCapacity));
,即将elementData
从索引0开始的Math.min(size, newCapacity)
个元素,复制到newElementData
从索引0开始的位置。
对性能的影响
- 时间复杂度:复制过程时间复杂度为O(n),因为要遍历原数组的所有元素并复制到新数组,n为原数组元素个数。在数组元素较多时,复制操作会消耗一定时间。
- 空间复杂度:扩容时会创建新数组,在复制过程中,原数组和新数组同时占用内存,直到复制完成原数组被垃圾回收,这在短时间内会增加内存开销。
高并发场景下可能出现的问题
- 数据不一致:如果多个线程同时对
ArrayList
进行添加操作导致扩容,可能会出现数据覆盖或丢失。例如线程A和线程B同时触发扩容,A先完成复制,B后完成复制,可能B复制的数据覆盖了A添加的部分数据。 - 扩容混乱:不同线程可能会同时判断需要扩容并各自创建新数组进行复制,造成资源浪费且可能导致最终数组状态混乱。
- 线程安全问题:
ArrayList
本身不是线程安全的,在高并发下对其扩容操作没有同步机制,除了上述数据问题,还可能引发其他线程安全问题,如迭代过程中数组结构变化导致ConcurrentModificationException
异常。