我有以下情况:
我需要一个列表或任何东西来存储许多对象。
它们都是由一个包含列表本身的类生成的。
现在我在其他线程中至少有一个(但可能更多)类,它们总是想从列表中的第一个对象开始,并定期(20ms-100ms)获取下一个对象。
该列表随着时间的推移而增长。最后可以有多达 300k 个对象。(其中一个对象最多可以包含 50 个整数或类似的东西)
具有自己的迭代器实现的 ConcurrentLinkedQueue 是正确的方法吗?需要自己的迭代器来拒绝删除选项?
我有以下情况:
我需要一个列表或任何东西来存储许多对象。
它们都是由一个包含列表本身的类生成的。
现在我在其他线程中至少有一个(但可能更多)类,它们总是想从列表中的第一个对象开始,并定期(20ms-100ms)获取下一个对象。
该列表随着时间的推移而增长。最后可以有多达 300k 个对象。(其中一个对象最多可以包含 50 个整数或类似的东西)
具有自己的迭代器实现的 ConcurrentLinkedQueue 是正确的方法吗?需要自己的迭代器来拒绝删除选项?
如果您有 1 位作者和多个读者在列表增长时对其进行迭代,那么是的,我绝对建议使用ConcurrentLinkedQueue
. 它是为队列上的多个并发操作而设计的。
您不能使用Collections.synchronizedList
,因为Javadocs 特别警告在修改列表时迭代:
用户在迭代返回的列表时必须手动同步它:
显然,ConcurrentLinkedQueue
随着队列变得庞大(300k 个项目),迭代器是一种可行的方法。小心Queue
导致程序运行整个队列以查找条目等的方法。
另一个需要考虑的选项是ConcurrentSkipListMap
在 Java 6+ 中可用。虽然它是一个 log2 查找映射,但它也有有序条目,因此迭代与队列相同。这允许您同时对集合执行映射和队列操作。跳过列表++。
编辑:
需要自己的迭代器来拒绝删除选项?
如果您询问是否需要覆盖迭代器以不允许删除,那么可以。您可能会考虑扩展整个Queue
以返回您自己的自定义委托迭代器并阻止Queue.remove(...)
。
由于只有一位作者和许多读者,您可以考虑使用CopyOnWriteArrayList
. 从文档中:
一种线程安全的变体,
ArrayList
其中所有可变操作(添加、设置等)都是通过制作底层数组的新副本来实现的。这通常成本太高,但是当遍历操作的数量大大超过突变时,它可能比替代方法更有效,并且在您不能或不想同步遍历但需要排除并发线程之间的干扰时很有用。“快照”风格的迭代器方法使用对创建迭代器时数组状态的引用。这个数组在迭代器的生命周期内永远不会改变,所以干扰是不可能的,并且迭代器保证不会抛出
ConcurrentModificationException
。
编辑:正如格雷指出的那样,插入的绝对数量使得这个解决方案令人望而却步——我会选择他的解决方案。