这种LILO最有效的收集?

时间:2009-02-16 14:02:45

标签: java data-structures

我正在编制一个与客户端通信的最新网络消息列表。基本上我只想要一个存储多达X个消息对象的列表。列表达到所需大小后,应删除列表中最旧的(第一个)项。该集合需要维持其顺序,我需要做的就是

  1. 遍历它,
  2. 将项目添加到最后,
  3. 如果#2过长,则从头开始删除项目。
  4. 这样做最有效的结构/数组/集合/方法是什么?谢谢!

8 个答案:

答案 0 :(得分:10)

您想使用Queue

答案 1 :(得分:3)

我不认为LILO是真正的术语......但你正在寻找一个FIFO队列

答案 2 :(得分:1)

您可以使用ArrayList。今天的计算机以这样的速度复制数据,除非你的列表包含数十亿个元素,否则无关紧要。

性能信息:在我的双核上复制1000万个元素需要13ms (thirteen milliseconds)。因此,即使是关于最佳数据结构的第二步,也要浪费,除非您的用例有很大差异。在这种情况下:您拥有超过1000万个元素,除了插入和删除元素之外,您的应用程序不做任何其他操作。如果您对插入/移除的元素进行任何操作,则可能会在此操作中花费的时间超过插入/移除的成本。

链接列表乍一看似乎更好,但是在分配内存时需要更多时间,而且代码更复杂(所有指针都更新)。所以运行时更糟糕。在Java中使用LinkedList的唯一好处是该类已经实现了Queue接口,因此在代码中使用它更自然(使用peek()和pop())。

[编辑]那么让我们来看看效率。什么是效率?最快的算法?花费最少的行(因此具有最少量的错误)的那个?最容易使用的算法(=开发人员方面的代码量最少+错误更少)?表现最好的算法(并不总是最快的算法)?

让我们看一些细节:LinkedList实现Queue,因此使用该列表的代码更简单(list.pop()而不是list.remove(0))。但LinkedList将为每个add()分配内存,而ArrayList仅为每N个元素分配一次内存。为了进一步减少这一点,ArrayList将分配N * 3/2元素,因此随着列表的增长,分配的数量将缩小。如果您事先知道列表的大小,ArrayList将只分配一次内存。这也意味着GC清理的杂乱程度较低。因此,从性能的角度来看,ArrayList在一般情况下会胜出一个数量级。

只有当多个线程访问数据结构时,才需要同步版本。在Java 5中,许多人都看到了显着的速度提升。如果您有几个线程放置和弹出,请使用ArrayBlockingQueue,但在这种情况下,LinkedBlockingQueue可能是一个选项,尽管分配性能不佳,因为实现可能允许同时从两个不同的线程推送和弹出时间只要队列大小> = 2(在这种特殊情况下,to线程将不必访问相同的指针)。要做出决定,唯一的选择是运行一个分析器并测量哪个版本更快。

那就是说:除非得到测量的支持,否则任何有关性能的建议都会在90%的时间内出错。今天的系统已经变得如此复杂,在背景中发生了很多事情,以至于人类不可能理解甚至列举所有发挥作用的因素。

答案 3 :(得分:1)

我的第二个@ rich-adams re:Queue。特别是,既然你提到了对网络消息的响应,我想你可能想要一些能够很好地处理并发性的东西。查看ArrayBlockingQueue

答案 4 :(得分:1)

根据您的第三个要求,我认为您将不得不扩展或包装现有的实施,我建议您从ConcurrentLinkedQueue开始。

使用任何类型的阻塞队列的其他建议正在引导您走错路。阻塞队列不允许您将元素添加到完整队列,直到删除另一个元素。此外,它们在等待该操作发生时阻塞。根据您自己的要求,这不是您想要的行为。您希望在将新元素添加到完整队列时自动删除第一个元素。

在ConcurrentLinkedQueue周围创建一个包装器应该相当简单,重写offer方法来检查size和容量(你的包装器类将保持容量)。如果它们相等,那么您的offer方法将需要轮询队列以在添加新元素之前删除第一个元素。

答案 5 :(得分:0)

你可以使用一个普通的旧ArrayList。 添加时,只需执行(假设ArrayList称为al)

if (al.size() >= YOUR_MAX_ARRAY_SIZE)
{
  al.remove(0);
}

答案 6 :(得分:0)

我认为您希望实现一个Queue<E>,其中您有窥视,拉动和移除方法,就好像头上没有任何东西,直到计数超过您想要的阈值。您可能想要包装一个现有的实现。

答案 7 :(得分:-1)

LinkedList应该是您正在寻找的