我在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,所以如果其中有一个我还没有听说过的好收藏,请参考我。
那么:有什么好主意如何有效,干净地解决这个问题?
最佳答案
如果您总是要整体使用WINDOW_SIZE / 2事件,那么为什么生产者线程(您说只有一个)不填充大小为WINDOW_SIZE / 2的数组,并在数组填满后将其传递给队列?