滑动窗口与生产者/消费者线程重叠50%

时间:2013-01-16 10:34:48

标签: java android guava concurrent-collections

我在Java中有以下场景:

  • 1个生成器线程将事件对象存储到队列中。阻止它不是一种选择。它应该始终只是将每个元素存储在队列的末尾并退出(因此没有有界队列)。
  • 1个消费者线程等待队列中包含WINDOW_SIZE个事件数。然后它应该从队列中检索所有WINDOW_SIZE事件以进行处理,但只删除其中的一半(即WINDOW_SIZE / 2),重叠50%。

我的问题是,您将使用哪个(并发)集合来有效地实现此目的?这些事件在资源有限的设备(运行Android的手机)上以100Hz的频率进行。我想过使用以下内容,其中没有一个看起来合适:

  1. ConcurrentLinkedQueue,每次修改时检查队列大小,并在WINDOW_SIZE事件可用时在使用者中使用peek()/ poll()。这看起来有点麻烦。
  2. 一个ArrayBlockingQueue,再次检查队列大小,并使用drainTo()。但是,该方法具有以下文档:“[...]此外,如果在操作正在进行时修改指定的集合,则此操作的行为是未定义的。[...]”。这对于并发集合来说似乎有点奇怪。
  3. 以下是一些示例代码:

    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();
            }
        }
    }
    

    顺便说一下,我也在使用谷歌番石榴,所以如果有一个很好的收藏,我没有听说过,请转介我。

    那么:任何好的想法如何有效而干净地解决这个问题?

1 个答案:

答案 0 :(得分:1)

如果你总是要消耗WINDOW_SIZE / 2事件 en bloc ,为什么生产者线程(你说只有一个)没有填充一个大小为WINDOW_SIZE / 2的数组并传递它一旦它满了就加入队列?