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();
}
调用作为上一个操作。
根据我对文档的理解,这是不正确的并且可能有害,因为通道不是线程安全的,这种行为可能会搞砸。但那我该怎么做呢?我的意思是,我有一些想法,但他们会让一切变得更加复杂,我想知道它是否真的有必要。
提前致谢
答案 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));
}
}
_channelMutex
是protected final Object _channelMutex = new Object();
用类创建。 see github code for AMQChannel.java
修改强>
正如您可以在官方文档中看到的那样,“某些”操作是线程安全的,现在还不清楚哪些操作。 我研究了代码,我认为在更多线程上调用ACK没有问题。
希望它有所帮助。
<强> EDIT2 强> 我还添加了Nicolas的评论:
请注意,从多个线程中使用(basicConsume)和acking是java客户端已经使用的常见rabbitmq模式。
所以你可以安全地使用它。