我有一个项目跟踪超过500k对象的状态信息,程序接收关于这些对象的10k更新/秒,更新包括新的,更新或删除操作。
作为程序的一部分,必须大约每五分钟对这些对象执行一次内部管理,为此,我将它们放在实现DelayQueue
接口的Delayed
中,允许阻塞功能DelayQueue
来控制这些物品的保管。
新的时候,对象会放在DelayQueue
。
更新后,对象为remove()
来自DelayQueue
,已更新,然后重新插入其更新信息所指示的新位置。
删除后,remove()
中的对象为DelayQueue
。
我面临的问题是,一旦队列传递了大约450k个对象,remove()
方法就会变得非常长。
该程序是多线程的,一个线程处理更新,另一个线程处理内容。由于remove()
延迟,我们遇到了令人讨厌的锁定性能问题,并且最终更新线程缓冲区消耗了所有堆空间。
我设法通过创建DelayedWeakReference (extends WeakReference implements Delayed)
来解决这个问题,它允许我将“影子”对象留在队列中,直到它们正常到期为止。
这会消除性能问题,但会导致内存需求大幅增加。这样做会导致实际需要在队列中的每个对象大约5 DelayedWeakReference
。
是否有人知道DelayQueue
有额外的跟踪功能,可以进行快速remove()
操作?或者有什么建议可以更好地处理这个问题,而不会消耗更多的内存?
答案 0 :(得分:2)
我花了一些时间考虑这个,
但在阅读了你有趣的问题几分钟之后,这是我的想法:
A.如果你的对象有某种ID,用它来散列,实际上没有一个延迟队列,但有N个延迟队列。
这将使锁定系数降低N.
将有一个中央数据结构,
持有这N个队列。由于N是预先配置的,因此
您可以在系统启动时创建所有N个队列。
答案 1 :(得分:1)
如果你只需要“大约每五分钟”进行一次家务管理,这就是维持这种情况所需的工作。
我要做的是有一个任务,每分钟运行一次(或根据需要减少),以查看自上次更新以来是否已经过了五分钟。如果使用此方法,则无需维护其他集合,并且更新时不会更改任何数据结构。扫描组件的开销增加,但是不变。执行更新的开销变得微不足道(设置上次更新的字段)
答案 2 :(得分:0)
如果我理解你的问题,你想对某个对象做一些事情,如果它没有被触摸过5分钟。
您可以拥有自定义链接列表;尾巴是最近感动的。删除节点很快。
簿记线程可以每1秒唤醒一次,并移除5分钟的头部。但是,如果1秒延迟是不可接受的,则计算确切的暂停时间
// book keeping thread
void run()
synchronized(list)
while(true)
if(head==null)
wait();
else if( head.time + 5_min > now )
wait( head.time + 5_min - now );
else
remove head
process it
// update thread
void add(node)
synchronized(list)
append node
if size==1
notify()
void remove(node)
synchronized(list)
remove node