work模型
称为工作队列或者竞争消费者模式,多个消费者消费的数据之和才是原来队列中的所有数据,适用于流量的消峰
生产者的编写
public class Producer {
private static final String QUEUE_NAME = "queue_work_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 向队列发送消息
for (int i = 0; i < 100; i++) {
channel.basicPublish("", QUEUE_NAME, null, ("work消息模型:"+i).getBytes());
}
channel.close();
connection.close();
}
}
消费者
// 消费者1
public class Consumer {
private static final String QUEUE_NAME = "queue_work_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// channel.basicQos(1);
// 声明消费者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1接受到的消息是:" + new String(body));
//进行手动应答
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
// 绑定消费者
channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
}
}
// 消费者2
public class Consumer2 {
private static final String QUEUE_NAME = "queue_work_1";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// channel.basicQos(1);
// 声明消费者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者2接受到的消息是:" + new String(body));
//进行手动应答
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
// 绑定消费者
channel.basicConsume(QUEUE_NAME, false, defaultConsumer);
}
}
测试结果
运行的时候可以看出 消费者1 几乎是瞬间完成,消费者2则是慢慢吞吞的运行完毕,消费者1大量时间处于空闲状态,消费者2则一直忙碌。这显然是不适用于实际开发中。
我们需要遵从一个原则,就是 能者多劳 ,消费越快的人,消费的越多。
能者多劳
修改消费者的代码,两个都添加上 以下代码
channel.basicQos(1);
运行结果:
channel.basicQos()
/**
* @param prefetchSize maximum amount of content (measured in
* octets) that the server will deliver, 0 if unlimited
* @param prefetchCount maximum number of messages that the server
* will deliver, 0 if unlimited
* @param global true if the settings should be applied to the
* entire channel rather than each consumer
*/
void basicQos(int prefetchSize, int prefetchCount, boolean global) throws IOException;
- param1:prefetchSize,预取大小服务器将传递的最大内容量(以八位字节为单位),如果不受限制,则为0
- 默认值:0
- param2:prefetchCount,服务器一次请求将传递的最大邮件数,如果没有限制,则为0
- 调用此方法时,该值必填。默认值:0
- param3:global,是否将设置应用于整个频道,而不是每个消费者
- 默认值:false,应用于本身(一个消费者)
- true:应用于整个频道
RabbitMQ通讯模型系列
RabbitMQ从零开始学(二)—通信模型之HelloWorld型—channel方法参数详解
RabbitMQ从零开始学(四)—通信模型之发布订阅模型—channel.exchangeDeclare()—channel.queueBind()
RabbitMQ从零开始学(五)—通信模型之路由模型(direct)
RabbitMQ从零开始学(六)—通信模型之topic模型—通信模型总结