0

我在Java中有以下场景:

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

我的问题是,您将使用哪个(并发)集合来有效地实现这一点?这些事件在资源有限的设备(运行 Android 的手机)上以 100Hz 的频率出现。我想过使用以下内容,但似乎都不合适:

  1. ConcurrentLinkedQueue,每次修改时检查队列大小,并在 WINDOW_SIZE 事件可用时在消费者中使用 peek()/poll()。这似乎有点麻烦。
  2. 一个 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,所以如果那里有我没听说过的不错的收藏,请参考我。

所以:有什么好主意如何有效和干净地解决这个问题?

4

1 回答 1

1

If you're always going to consume WINDOW_SIZE/2 events en bloc, why doesn't the producer thread (you said there's only one) fill an array of size WINDOW_SIZE/2 and pass it to the queue once it's full?

于 2013-01-16T10:39:18.143 回答