RabbitMQ和渠道Java线程安全

时间:2015-06-07 15:35:38

标签: java multithreading rabbitmq

本指南中的

https://www.rabbitmq.com/api-guide.html RabbitMQ的人说:

  

频道和并发注意事项(线程安全)

     

不得在线程之间共享通道实例。应用程序应该更喜欢每个线程使用一个Channel,而不是跨多个线程共享相同的Channel。虽然通道上的某些操作可以安全地同时调用,但有些操作并不会导致错误的帧交错。在线程之间共享通道也会干扰* Publisher Confirms。

线程安全非常重要,所以我尽量保持勤奋,但问题在于:

我有这个应用程序从Rabbit接收消息。收到消息后,它会对其进行处理,然后在完成消息时确认。应用程序可以在具有2个线程的固定线程池中同时处理2个项目。 Rabbit的QOS预取设置为2,因为我不想在一个时间范围内为应用程序提供超过它的处理能力。

现在,我的消费者的handleDelivery执行以下操作:

channel.basicAck(deliveryTag, false);

此时,您已经发现TestWrapperThread将//Asuming that your activiy is named MainActivity new Thread(new Runnable() { public void run() { try { pos = Calculo.Calcular(); //Manipulate your UI elements as following MainActivity.this.runOnUiThread(new Runnable() { public void run() { mostrarFrases(pos); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } 调用作为上一个操作。

根据我对文档的理解,这是不正确的并且可能有害,因为通道不是线程安全的,这种行为可能会搞砸。但那我该怎么做呢?我的意思是,我有一些想法,但他们会让一切变得更加复杂,我想知道它是否真的有必要。

提前致谢

1 个答案:

答案 0 :(得分:11)

我认为您仅为您的消费者使用Channel而不是用于发布等其他操作。

在您的情况下,唯一可能存在的问题是:

channel.basicAck(deliveryTag, false);

因为你跨两个线程调用它,顺便说一下这个操作是安全的,如果你看到java代码:

班级ChannelN.java来电:

public void basicAck(long deliveryTag, boolean multiple)
   throws IOException
{
   transmit(new Basic.Ack(deliveryTag, multiple));
}

see github code for ChannelN.java

AMQChannel中的transmit方法使用:

public void transmit(Method m) throws IOException {
   synchronized (_channelMutex) {
       transmit(new AMQCommand(m));
   }
}

_channelMutexprotected final Object _channelMutex = new Object();

用类创建。 see github code for AMQChannel.java

修改

正如您可以在官方文档中看到的那样,“某些”操作是线程安全的,现在还不清楚哪些操作。 我研究了代码,我认为在更多线程上调用ACK没有问题。

希望它有所帮助。

<强> EDIT2 我还添加了Nicolas的评论:

请注意,从多个线程中使用(basicConsume)和acking是java客户端已经使用的常见rabbitmq模式。

所以你可以安全地使用它。