从ActiveMQ DestinationSource.getQueues响应中正确迭代队列

时间:2015-07-08 16:34:24

标签: java concurrency set activemq copyonwritearraylist

出于某些原因,在以下代码中,destinationSource.getQueues()返回的是CopyOnWriteArraySet,而不是简单的Set。这是一个问题,因为for循环在Set已满之前开始处理,由于CopyOnWriteArraySet的性质,它只会在循环之前处理Set中的项目。我知道我可以在那里抛出Thread.sleep(),但这并不能解决潜在的问题。是否有任何理由将其作为CopyOnWriteArraySet而不是Set返回?还有什么方法可以迭代CopyOnWriteArraySet以确保所有项目都被覆盖,甚至是在迭代期间添加的项目?

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
ActiveMQConnection activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection();
activeMQConnection.start();
DestinationSource destinationSource = activeMQConnection.getDestinationSource();

Set<ActiveMQQueue> queues = destinationSource.getQueues();

for(ActiveMQQueue queue : queues) {
  queueNames.add(queue.getPhysicalName());
}

activeMQConnection.close()

编辑:这是我提出的解决方案,虽然它并不完美,但它确保您可以获得所有队列,直到添加队列之间的时间超过1秒。

    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);

    ActiveMQConnection activeMQConnection = (ActiveMQConnection) connectionFactory.createConnection();

    activeMQConnection.start();

    DestinationSource destinationSource = activeMQConnection.getDestinationSource();

    Set<ActiveMQQueue> queues = destinationSource.getQueues();

    do {
        for(ActiveMQQueue queue : queues) {
            String physcialName = queue.getPhysicalName();
            if(!queueNames.contains(physcialName)) {
                queueNames.add(physcialName);
            }
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log(e.toString());
        }
    }while(queueNames.size() < queues.size());

    activeMQConnection.close();

2 个答案:

答案 0 :(得分:3)

从连接中获取所有队列时遇到了同样的问题。 每当我从DestinationSource获得队列,然后在此集合之后迭代(foreach), 我得到了不同数量的队列(在迭代循环中,我总是得到比初始队列更多的队列)。

DestinationSource ds = connection.getDestinationSource();
Set<ActiveMQQueue> queues = ds.getQueues();
log.debug("Found '" + queues.size() + "' queues");
for (ActiveMQQueue queue : queues) {...}

然后,我像这样添加了一个目标源的监听器

DestinationSource ds = connection.getDestinationSource();
Set<ActiveMQQueue> queues = ds.getQueues();
// Add listener:
ds.setDestinationListener(event -> event.hashCode());
log.debug("Found '" + queues.size() + "' queues");
for (ActiveMQQueue queue : queues) {...}

从现在开始,我总能获得正确数量的队列,并且可以遍历整个队列。

尽管如此,我真的不知道为什么;)

答案 1 :(得分:1)

正如你所说,CopyOnWriteArraySet以这种方式行事的本质。队列列表可以与您的线程同时更改。通过返回CopyOnWriteArraySet ActiveMQ,您将获得一个可在您的线程中安全使用的数据结构(不会更改ConcurrentModificationException),并且会保持最新状态。

由于可以随时添加新队列,因此在完成所有队列之前无法“等待”。

如果您想知道何时添加新队列然后做出响应,最好的方法是听取相应的ActiveMQ advisory message。此工具将允许您响应消息队列添加,消费者和生产者添加,以及删除它们。 Think link有一个代码示例。