背景

我正在尝试使用Apache Commons库中的CircularFifoBuffer类,该类包含通过WebSocket连接接收的最新消息的集合。但是,当我在Linux部署中达到CircularFifoBuffer的大小限制时,就会抛出BufferOverflowException

我对Java还是很陌生,但是这是定义CircularFifoBuffer实例变量的方式:

private static Buffer<String> recentWebSocketMessages = new CircularFifoBuffer<String>(1000);


这是一个例外:

org.apache.commons.collections15.BufferOverflowException: The buffer cannot hold more than 1000 objects.
 at org.apache.commons.collections15.buffer.BoundedFifoBuffer.add(BoundedFifoBuffer.java:218)
 at org.apache.commons.collections15.buffer.CircularFifoBuffer.add(CircularFifoBuffer.java:94)
 at com.example.SystemMonitor.putRecentWebSocketMessage(SystemMonitor.java:228)


对我来说奇怪的是,当我编写一个无限循环时,这个问题是间歇性的:

while(true)
{
    recentWebSocketMessages.add("TESTING");
}


不会发生该异常(至少在Windows中-我尚未能够测试Linux)



所以我想这里的主要问题是为什么这个问题是间歇性的,我可以通过定义静态变量来解决这个问题吗? (即使这将recentWebSocketMessagesCircularFifoBufferBoundedFifoBuffer实现紧密结合在一起)

private static CircularFifoBuffer<String> recentWebSocketMessages = new CircularFifoBuffer<String>(1000);


编辑

谢谢sorifiend和Tom指出这个实现未同步的简单事实。对于那些感兴趣的人,下面的这个简单线程示例证明了多线程是问题所在,同时访问缓冲区的多个线程可能/将导致BufferOverflowException发生(使用我最初对缓冲区的定义):

while(true)
{
    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                recentWebSocketMessages.add("TESTING");
            }
            catch(BufferOverflowException e)
            {
                e.printStackTrace();
            }
        }
    }).start();
}


具有以下recentWebSocketMessages定义的相同代码不会抛出BufferOverflowException,因为如API和sorifiend的回答中所述,对缓冲区的访问是同步的:

Buffer recentWebSocketMessages = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(1000));

最佳答案

快速回答:不,像那样更改它不会真正有帮助。

测试消息不会引起问题,因为应该自动删除项目以增加空间:


  CircularFifoBuffer是大小固定的先进先出缓冲区
  如果已满,将替换其最早的元素。
  
  CircularFifoBuffer的删除顺序基于插入
  订购;元素将按照它们被删除的相同顺序删除
  添加。迭代顺序与删除顺序相同。


但是,我相信在达到缓冲区限制(以1000为例)的情况下,为Web套接字使用多个线程时有时会出现问题。

如果这是您的问题,那么最好的解决方法是像这样进行同步:

Buffer recentWebSocketMessages = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(1000));

而不是您当前的操作方式:

Buffer<String> recentWebSocketMessages = new CircularFifoBuffer<String>(1000);



复制的表格API:
https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.2/org/apache/commons/collections/buffer/CircularFifoBuffer.html

07-24 18:45