gpt4 book ai didi

java - ConcurrentLinkedQueue$Node 在 remove() 之后保留在堆中

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:16:51 25 4
gpt4 key购买 nike

我有一个写入和读取 ConcurrentLinkedQueue 的多线程应用程序,它在概念上用于支持列表/表中的条目。我最初为此使用了 ConcurrentHashMap,效果很好。一项新要求需要跟踪进入的订单条目,因此可以根据某些条件以最旧的顺序删除它们。 ConcurrentLinkedQueue 似乎是一个不错的选择,而且在功能上它运行良好。

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

似乎正在发生的事情是我在发生的队列前面有一个条目,比如 100K 条目之前。该队列似乎配置的条目数量有限(size() == 100),但在分析时,我发现内存中有约 100K 个 ConcurrentLinkedQueue$Node 对象。这似乎是设计使然,只需看一眼 ConcurrentLinkedQueue 的源代码,删除操作只会删除对正在存储的对象的引用,但会保留链表以供迭代。

最后我的问题是:是否有一种“更好”的懒惰方式来处理这种性质的集合?我喜欢 ConcurrentLinkedQueue 的速度,我只是无法承受在这种情况下似乎可能出现的无限泄漏。如果没有,我似乎必须创建第二个结构来跟踪订单并且可能会遇到相同的问题,加上同步问题。

最佳答案

这里实际发生的是 remove 方法准备一个轮询线程来清空链接引用。

ConcurrentLinkedQueue 是一个非阻塞线程安全队列实现。但是,当您尝试从队列中轮询节点时,它是一个具有两个功能的过程。首先将值置空,然后将引用置空。 CAS 操作是单个原子函数,不会为轮询提供即时解决方案。

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

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

回答你的最后一个问题。不幸的是,没有更好的方法来实现删除和维护队列的非阻塞状态。至少在这一点上是这样。一旦处理器开始推出 2 路和 3 路套管,那么这是可能的。

关于java - ConcurrentLinkedQueue$Node 在 remove() 之后保留在堆中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2547161/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com