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

Java监听器实现的先行发生关系:是否会遗漏集合条目?

多线程场景下的条目遗漏问题分析

以下是某Java应用的部分代码:

final List<String> strings = new CopyOnWriteArrayList<>();
volatile Consumer<? super String> listener;

void add(String s) {
    strings.add(s);
    Consumer<? super String> l = listener;
    if (l != null) {
        l.accept(s);
    }
}

add(String s)方法可由多线程调用,将s加入CopyOnWriteArrayList(也可为其他线程安全Collection),若存在listener则以s为参数调用它。注意listener是volatile类型。

某一时刻,任意线程会调用一次如下的setupListener()方法:

void setupListener() {
    listener = System.out::println;
    strings.forEach(System.out::println);
}

setupListener()方法设置listener,并通过遍历已添加的strings处理之前未触发的监听器调用。

问题

假设setupListener()方法在某一时刻被调用一次,该代码是否可能因竞态条件导致strings中的条目被遗漏(即某一条目未被打印)?

注:已知竞态条件下strings条目可能被打印两次或顺序混乱,这是允许的,仅关心是否会有遗漏。另外,此问题不涉及同步或其他锁机制,无法修改上述代码,也不会调用它,只能设置listener。

个人论证

认为不会有条目遗漏,理由如下:假设某字符串s被遗漏,说明在add方法中listener被读取为null(否则它会被打印)。但由于:

  • 将s加入strings 先行于 将listener读取为null
  • 将listener读取为null 先行于 在setupListener方法中设置listener
  • 在setupListener方法中设置listener 先行于 遍历并打印strings

那么遍历strings时s一定会被打印,因为strings包含s,这与s被遗漏的假设矛盾。

请问该论证是否正确?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:43:26