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
相关产品推荐
相关产品推荐

