Apache Commons - CircularFifoBuffer BufferOverflowException

Apache Commons - CircularFifoBuffer BufferOverflowException

背景

我正在尝试使用 Apache Commons 库中的 CircularFifoBuffer class,它包含通过 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)

问题

所以我想这里的主要问题是为什么这个问题是间歇性的,我可以通过定义静态变量来解决这个问题吗? (尽管这将 recentWebSocketMessagesBoundedFifoBufferCircularFifoBuffer 实现紧密耦合)

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

编辑

感谢 sorifiend 和 Tom 指出这个实现不同步的简单事实。对于那些感兴趣的人,下面这个简单的线程示例证明了多线程是问题所在,多个线程同时访问缓冲区 can/will 导致 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));

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

测试消息不会导致问题,因为项目应该自动删除以添加 space:

CircularFifoBuffer is a first in first out buffer with a fixed size that replaces its oldest element if full.

The removal order of a CircularFifoBuffer is based on the insertion order; elements are removed in the same order in which they were added. The iteration order is the same as the removal order.

但是我认为,当您达到缓冲区限制(在您的情况下为 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