单个数据存储的多个消息侦听器。高效设计

时间:2015-07-31 09:09:54

标签: java multithreading performance rabbitmq message-listener

我有一个由多个消息监听器写入的数据存储。这些消息监听器中的每一个也可以在数百个单独的线程中。

数据存储是PriorityBlockingQueue,因为它需要通过时间戳对插入的对象进行排序。为了有效地检查项目队列而不是循环队列,使用并发hashmap 作为索引的形式。

private Map<String, SLAData> SLADataIndex = new ConcurrentHashMap<String, SLAData>();;
private BlockingQueue<SLAData> SLADataQueue;

问题1 这是一个可以接受的设计,还是应该使用单个PriorityBlockingQueue。

每个消息侦听器都执行一个操作,这些侦听器扩展到多个线程。

插入方法,以便插入两者。

this.SLADataIndex.put(dataToWrite.getMessageId(), dataToWrite);
this.SLADataQueue.add(dataToWrite);

更新方法

this.SLADataIndex.get(messageId).setNodeId(
            updatedNodeId);

删除方法

SLATupleData data = this.SLADataIndex.get(messageId);
//remove is O(log n)
this.SLADataQueue.remove(data);
// remove from index
this.SLADataIndex.remove(messageId);

问题二使用这些方法是最有效的方法吗?它们通过另一个对象围绕它们进行包装以进行错误处理。

问题三使用并发HashMap和BlockingQueue这是否意味着这些操作是线程安全的?我不需要使用锁定对象?

问题四当多个线程和侦听器调用这些方法而没有任何类型的同步块时,它们是否可以由不同的线程或侦听器同时调用?

1 个答案:

答案 0 :(得分:0)

  

问题1这是一个可接受的设计,还是我应该使用单个PriorityBlockingQueue。

当然,你应该尝试使用单个Queue。保持两个集合同步将需要更多的同步复杂性并担心代码。

为什么需要Map?如果只是调用setNodeId(...)那么我会让处理线程在从Queue拉出时自己做。

// processing thread
while (!Thread.currentThread().isInterrupted()) {
   dataToWrite = queue.take();
   dataToWrite.setNodeId(myNodeId);
   // process data
   ...
}
  

问题二使用这些方法这是最有效的方法吗?他们通过另一个对象来绕过它们进行错误处理。

当然,这似乎很好,但是,再次,您需要进行一些同步锁定,否则您将遇到race conditions使两个集合保持同步。

  

问题三使用并发HashMap和BlockingQueue这是否意味着这些操作是线程安全的?我不需要使用锁定对象吗?

这两个类(ConcurrentHashMapBlockingQueue实现)都是线程安全的,是的。 但是,因为有两个,你可以有一个竞争条件,其中一个集合已经更新但另一个没有。最有可能的是,您必须使用锁定对象来确保两个集合都正确保持同步。

  

问题四当多个线程和监听器调用这些方法而没有任何类型的同步块时,它们是否可以被不同的线程或监听器同时调用?

在没有看到相关代码的情况下,这是一个难以回答的问题。例如。有人可能正在调用Insert(...)并已将其添加到Map但尚未添加到queue,当另一个线程调用Delete(...)时,该项目将在{Map中找到1}}并删除但queue.remove()在队列中找不到它,因为Insert(...)尚未在另一个帖子中完成。