我在Java中有以下场景:
- 1 个生产者线程将事件对象存储到队列中。阻止它不是一种选择。它应该始终只将每个元素存储在队列的末尾并退出(因此没有有界队列)。
- 1 个消费者线程等待队列中包含 WINDOW_SIZE 个事件。然后它应该从队列中检索所有 WINDOW_SIZE 事件以进行处理,但只删除其中的一半(即 WINDOW_SIZE/2),以获得 50% 的重叠。
我的问题是,您将使用哪个(并发)集合来有效地实现这一点?这些事件在资源有限的设备(运行 Android 的手机)上以 100Hz 的频率出现。我想过使用以下内容,但似乎都不合适:
- ConcurrentLinkedQueue,每次修改时检查队列大小,并在 WINDOW_SIZE 事件可用时在消费者中使用 peek()/poll()。这似乎有点麻烦。
- 一个 ArrayBlockingQueue,再次检查队列大小,并使用 drainTo()。但是,该方法具有以下文档:“[...] 此外,如果在操作进行时修改了指定的集合,则此操作的行为是未定义的。[...]”。这对于并发集合来说似乎有点奇怪。
这是一些示例代码:
import java.util.Queue;
import com.google.common.collect.Queues;
public class AccelerometerProcessor implements Runnable {
private static final int WINDOW_SIZE = 128;
private final Queue<AccelerometerEvent> eventQueue = Queues.newConcurrentLinkedQueue();
@Override
public void run() {
while (!Thread.interrupted()) {
try {
synchronized (eventQueue) {
while (eventQueue.size() < WINDOW_SIZE) {
eventQueue.wait();
}
// We have WINDOW_SIZE eventQueue, start processing
}
} catch (InterruptedException e) {
// Do nothing
}
}
}
public void addAccelerometerEvent(AccelerometerEvent accelerometerEvent) {
synchronized (eventQueue) {
eventQueue.add(accelerometerEvent);
eventQueue.notifyAll();
}
}
}
顺便说一句,我也在使用 Google Guava,所以如果那里有我没听说过的不错的收藏,请参考我。
所以:有什么好主意如何有效和干净地解决这个问题?