昨天通宵上线代码,白天睡了一天,下午7.00才醒,做个饭继续学习。
接着上文最普通的队列一个生产者推送,一个消费者消费,如果一个生产者有多个消费者那会是什么样呢。
今天我用一个for循环生产50个消息来让消费者消费
package com.hc.work;
import com.hc.mqutil.MqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Product {
private static final String QUEUE_NAME="Work_Queue";
public static void main(String[] args) throws Exception {
//获取MQ和消息队列
Connection connection=MqUtil.getConnection();
Channel channel=connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
for(int i=0;i<50;i++){
String message="我是第"+i+"条消息";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(message);
Thread.sleep(i*10);
}
channel.close();
connection.close();
}
}
消费者一二的代码相似
package com.hc.work;
import com.hc.mqutil.MqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
public class Consumer1 {
private static final String QUEUE_NAME="Work_Queue";
public static void main(String[] args) throws Exception {
//获得连接--创建通道--声明队列
Connection connection=MqUtil.getConnection();
Channel channel=connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 同一时刻服务器只会发一条消息给消费者
// channel.basicQos(1);
QueueingConsumer consumer=new QueueingConsumer(channel);
// 监听队列, autoAck如果为true则为自动完成接收状态,不需要后续的处理,false手动返回完成状态
channel.basicConsume(QUEUE_NAME, false, consumer);
//channel.basicConsume(queue, autoAck, callback);
while(true){
QueueingConsumer.Delivery delivery=consumer.nextDelivery();
String message=new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
// 休眠1秒
Thread.sleep(1000);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}
消费者2
package com.hc.work;
import com.hc.mqutil.MqUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
public class Consumer2 {
private static final String QUEUE_NAME="Work_Queue";
public static void main(String[] args) throws Exception {
//获得连接--创建通道--声明队列
Connection connection=MqUtil.getConnection();
Channel channel=connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 同一时刻服务器只会发一条消息给消费者
channel.basicQos(1);
QueueingConsumer consumer=new QueueingConsumer(channel);
// 监听队列, autoAck如果为true则为自动完成接收状态,不需要后续的处理,false手动返回完成状态
channel.basicConsume(QUEUE_NAME, false, consumer);
//channel.basicConsume(queue, autoAck, callback);
while(true){
QueueingConsumer.Delivery delivery=consumer.nextDelivery();
String message=new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
// 休眠0.01秒
Thread.sleep(10);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
}
在我们注释掉channel.basicQos(1);时
我们启动生产者和消费者,发现一个消费者获取到的为奇数。另一个为偶数,刚好一人一半,但是2休眠的为0.1秒,1休眠的时1秒,这显然不合理
打开channel.basicQos(1),这时再测试我们发现2获取的明显比1多,这个方法保证了 同一时刻服务器只会发一条消息给消费者。
channel.basicConsume(queue, autoAck, callback);昨天我们第二个参数填的是true, 只要消息从队列中获取,无论消费者获取到消息后是否成功消息,都认为是消息已经成功消费。
false为手动确认 消费者从队列中获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,如果消费者一直没有反馈,那么该消息将一直处于不可用状态。代码注释仔细,可以自己测试实际效果。