11

我有一个项目可以跟踪超过 500k 个对象的状态信息,该程序每秒接收 10k 次关于这些对象的更新,更新包括新建、更新或删除操作。

作为程序的一部分,必须大约每五分钟对这些对象执行一次内务管理,为此我将它们放置在DelayQueue实现接口中,允许控制这些对象的内务Delayed处理的阻塞功能。DelayQueue

  • 在 new 上,一个对象被放置在DelayQueue.

  • 更新后,对象remove()从 'd' 中DelayQueue更新,然后重新插入到由更新信息指定的新位置。

  • 删除后,该对象remove()将从DelayQueue.

我面临的问题是,remove()一旦队列通过大约 450k 个对象,该方法就会变成一个非常长的操作。

该程序是多线程的,一个线程处理更新,另一个处理内务。由于remove()延迟,我们遇到了令人讨厌的锁定性能问题,最终更新线程缓冲区消耗了所有堆空间。

我设法通过创建一个来解决这个问题DelayedWeakReference (extends WeakReference implements Delayed),它允许我将“影子”对象留在队列中,直到它们正常过期。

这消除了性能问题,但会导致内存需求显着增加。这样做会导致DelayedWeakReference每个实际需要在队列中的对象大约 5 。

有人知道DelayQueue允许快速remove()操作的附加跟踪吗?或者有什么更好的方法来处理这个问题而不消耗更多的内存?

4

3 回答 3

3


花了我一些时间思考这个问题,
但是在阅读了你有趣的问题几分钟后,我的想法是:
A. 如果你的对象有某种 ID,用它来散列,实际上没有一个延迟队列,但有 N 个延迟队列。
这将使锁定因子减少 N。
将有一个中央数据结构,
保存这 N 个队列。由于 N 是预配置的,
因此您可以在系统启动时创建所有 N 个队列。

于 2012-11-16T17:00:50.393 回答
1

如果您只需要“大约每五分钟”执行一次内务管理,那么这就是维护它的工作量。

我要做的是有一个每分钟运行一次(或根据需要更少)运行的任务,以查看自上次更新以来是否已经过了五分钟。如果您使用这种方法,则无需维护额外的集合,并且更新时不会更改数据结构。扫描组件的开销增加了,但保持不变。执行更新的开销变得微不足道(设置最后一次更新的字段)

于 2012-11-16T16:58:38.253 回答
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    
于 2012-11-16T17:52:10.990 回答