You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java并发程序中ArrayList元素丢失问题的原理咨询

多线程下ArrayList元素丢失的底层原理分析

一、ArrayList的核心实现逻辑

ArrayList基于动态数组实现,内部有两个关键字段:

  • elementData:存储元素的底层数组
  • size:当前列表中已有的元素数量

它的add()方法核心逻辑可简化为:

public boolean add(E e) {
    // 确保数组容量足够容纳新元素
    ensureCapacityInternal(size + 1);
    // 先把元素放到数组的size位置,再将size自增1
    elementData[size++] = e;
    return true;
}

二、多线程竞态条件导致元素丢失的具体过程

当两个线程同时对同一个ArrayList执行add()操作时,会触发竞态条件,直接造成元素丢失,具体场景如下:
假设当前size为10,线程A和线程B同时执行add():

  1. 线程A执行ensureCapacityInternal(11),确认数组容量足够,准备执行elementData[10] = 'K',但还没执行size++就被CPU挂起。
  2. 线程B也执行ensureCapacityInternal(11),同样确认容量足够,直接执行elementData[10] = 'k',覆盖了线程A即将写入的位置,随后执行size++,size变为11。
  3. 线程A恢复执行,跳过容量检查(之前已完成),直接执行size++,size变为12。

最终结果:数组第10位仅保存了线程B的元素,线程A的'K'被覆盖丢失;但size却增加了2,实际只新增1个元素,所以最终列表总大小会比预期的52少1(比如你遇到的51)。

三、为什么调试时letter变量存在但元素丢失

你调试时看到addLetter的局部变量letter包含丢失的'K',是因为线程确实正确传递了该字符到addLetter方法中,但在ArrayList的add()操作里,赋值步骤被另一个线程覆盖,导致这个字符没有成功保存到底层数组,最终列表中看不到它。

四、解决方法

  • 改用线程安全的集合类:比如CopyOnWriteArrayList(适合读多写少场景),或者用Collections.synchronizedList(new ArrayList<>())包装ArrayList。
  • 给Data类的addLetter方法添加synchronized修饰,或者在调用addLetter时加锁,确保同一时间只有一个线程执行元素添加操作。

内容的提问来源于stack exchange,提问作者CDO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:05:20