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)
问题
所以我想这里的主要问题是为什么这个问题是间歇性的,我可以通过定义静态变量来解决这个问题吗? (尽管这将 recentWebSocketMessages
与 BoundedFifoBuffer
的 CircularFifoBuffer
实现紧密耦合)
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);
背景
我正在尝试使用 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)
问题
所以我想这里的主要问题是为什么这个问题是间歇性的,我可以通过定义静态变量来解决这个问题吗? (尽管这将 recentWebSocketMessages
与 BoundedFifoBuffer
的 CircularFifoBuffer
实现紧密耦合)
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);