我有一个编写和读取ConcurrentLinkedQueue的多线程应用程序,该概念在概念上用于备份列表/表中的条目。我最初为此使用了ConcurrentHashMap,效果很好。一项新的要求要求跟踪输入的订单,因此可以根据某些条件以最早的第一订单将其删除。 ConcurrentLinkedQueue似乎是一个不错的选择,并且在功能上也不错。

数量可配置的条目保存在内存中,并且在达到限制时提供新条目时,将以最早的优先顺序搜索队列中可以删除的条目。某些条目不会被系统删除,并等待客户端交互。

似乎正在发生的事情是,我在发生的队列的最前面有一个条目,例如100K条目。该队列似乎具有有限数量的已配置条目(size()== 100),但是进行概要分析时,我发现内存中有约100K ConcurrentLinkedQueue $ Node对象。这似乎是设计使然,只是浏览了ConcurrentLinkedQueue的源代码,删除仅删除了对要存储的对象的引用,但保留了链接列表以进行迭代。

最后,我的问题是:是否有一种“更好的”懒惰方式来处理这种性质的集合?我喜欢ConcurrentLinkedQueue的速度,但我负担不起这种情况下可能发生的无限制泄漏。如果没有,似乎我必须创建第二个结构来跟踪订单,并且可能有相同的问题以及同步问题。

最佳答案

实际发生的是remove方法准备一个轮询线程以使链接的引用无效。

ConcurrentLinkedQueue是一种非阻塞线程安全的Queue实现。但是,当您尝试从队列中轮询节点时,这是两个功能的过程。首先,您使该值无效,然后使引用无效。 CAS操作是单个原子功能,不会为轮询提供即时的分辨率。

轮询时发生的情况是,成功的第一个线程将获取节点的值并将该值设为null,然后该线程将尝试将引用设为null。然后可能会有另一个线程进入并尝试从队列中轮询。为确保此Queue拥有非阻塞属性(即一个线程的失败不会导致另一个线程的失败),新的传入线程将查看该值是否为null,如果该值为null,则该线程将使引用为空并尝试再次轮询()。

因此,您在这里看到的是remove线程只是在准备任何新的轮询线程以使引用为空。我想尝试实现非阻塞删除功能几乎是不可能的,因为这将需要三个原子功能。值的null为引用该节点的null的引用,最后为该节点的新引用为其父节点的父节点。

回答您的最后一个问题。没有多余的方法可以更好地实现删除和维护队列的非阻塞状态。至少在这一点上。一旦处理器开始使用2和3方式 shell ,那就有可能。

09-13 12:16