我有多个生产者线程,可以同时将对象添加到共享队列。
我想创建一个单线程使用者,从该共享队列中读取以进行进一步的数据处理(数据库批量插入)。
问题:我希望只在队列中获取队列中的数据,以便在批量插入期间获得更好的性能。因此,我不得不检测队列中有多少项,然后从队列中获取所有这些项,并再次清空队列。
BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<>();
ExecutorService pes = Executors.newFixedThreadPool(4);
ExecutorService ces = Executors.newFixedThreadPool(1);
pes.submit(new Producer(sharedQueue, 1));
pes.submit(new Producer(sharedQueue, 2));
pes.submit(new Producer(sharedQueue, 3));
pes.submit(new Producer(sharedQueue, 4));
ces.submit(new Consumer(sharedQueue, 1));
class Producer implements Runnable {
run() {
...
sharedQueue.put(obj);
}
}
class Consumer implements Runnable {
run() {
...
sharedQueue.take();
}
}
消费者的问题:如何轮询共享队列,等待具有X项的队列,然后获取所有项目并同时清空队列(这样消费者可以再次开始轮询和等待)?
我愿意接受任何建议,但不一定与上述代码绑定。
答案 0 :(得分:3)
我最近开发了这个实用程序,如果队列元素未达到批处理大小,则使用刷新超时对BlockingQueue元素进行批处理。 它还支持使用多个实例来细化同一组数据的fanOut模式:
// Instantiate the registry
FQueueRegistry registry = new FQueueRegistry();
// Build FQueue consumer
registry.buildFQueue(String.class)
.batch()
.withChunkSize(5)
.withFlushTimeout(1)
.withFlushTimeUnit(TimeUnit.SECONDS)
.done()
.consume(() -> (broadcaster, elms) -> System.out.println("elms batched are: "+elms.size()));
// Push data into queue
for(int i = 0; i < 10; i++){
registry.sendBroadcast("Sample"+i);
}
更多信息在这里!
答案 1 :(得分:1)
不是检查队列的大小,而是最好在使用者中创建内部List
并从队列中获取对象并添加到该列表中。一旦列表中有X项,您就进行处理,然后清空内部列表。
class Consumer implements Runnable {
private List itemsToProcess = new ArrayList();
run() {
while (true) { // or when producers are stopped and queue is empty
while (itemsToPorcess.size() < X) {
itemsToProcess.add(sharedQueue.take());
}
// do process
itemsToProcess.clear();
}
}
}
而不是BlockingQueue.take()
你可以使用BlockingQueue.poll(timeout)
一些合理的超时和检查null
的结果来检测所有生产者完成并且队列为空以便能够关闭你的情况消费者。