我在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的数组,并在数组填满后将其传递给队列?

09-25 19:24