上一篇讲了个 哈喽World,现在来看看如果存在多个消费者的情况。

生产者:

package com.example.demo;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* 竞争消费者模式
*/
public class CompetingSend { private static final String QUEUE_NAME = "hello"; public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory(); // 连接工厂
factory.setHost("localhost");
Connection connection = factory.newConnection(); // 获取连接
Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 声明队列,只有他不存在的时候创建
String msg = "Hello World!";
// 发送多条消息
for (int i = 0; i < 5; i++){
channel.basicPublish("", QUEUE_NAME, null, (msg + "-" + i).getBytes());
System.out.println("Sending:" + msg);
} channel.close();
connection.close(); }
}

消费者:

package com.example.demo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException; /**
* 一个生产者,多个消费者
*/
public class CompetingReceiveA { private static final String QUEUE_NAME = "hello"; public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory(); // 连接工厂
factory.setHost("localhost");
Connection connection = factory.newConnection(); // 获取连接
Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 声明队列,只有他不存在的时候创建 Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String recv = new String(body, "UTF-8");
System.out.println("Receive:" + recv);
try {
doWork(recv);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("Done");
}
}
}; // true代表接收到消息后,给兔子发消息,让这条消息失效
channel.basicConsume(QUEUE_NAME, true, consumer);
} // 模拟每条消息处理时间不一样
private static void doWork(String msg) throws InterruptedException {
char c = msg.charAt(msg.length() - 1);
for (int i = 0; i < Integer.parseInt(c+""); i++)
Thread.sleep(1000);
} }

先启动两个消费者,再启动生产者,查看控制台:

消费者A

消费者B

生产者(这里不必有疑问,这里打印的是修改之前的消息)

要说明的是什么观点呢?

默认情况下,RabbitMQ将按顺序将每条消息发送给下一个使用者。一般来说,每个消费者得到的消息是一样多。但是,并不是说每个消费者的任务重量是平均的。很有可能出现A总在处理耗时任务,B一直吃西瓜的情况。

因为兔子不知道每个消息的耗时,他就会傻傻的派遣任务。

不过,官方也有解决办法。

为了解决这个问题,我们可以使用basicQos方法,设置prefetchCount = 。这告诉RabbitMQ不要向消费者发送多于一条消息。换句话说,在它处理并确认了前一个消息之前,不要向工作人员发送新消息。

如果当前消费者正在忙碌(没有确认消息),它会将其分派给空闲下一个消费者。

int prefetchCount = 1;
channel.basicQos(prefetchCount);

RabbitMQ入门-竞争消费者模式的更多相关文章

  1. RabbitMQ入门-消息订阅模式

    消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...

  2. Competing Consumers Pattern (竞争消费者模式)

    Enable multiple concurrent consumers to process messages received on the same messaging channel. Thi ...

  3. RabbitMQ入门-发布订阅模式

    兔子的Publish/Subscribe是这样的: 有个生产者P,X代表交换机,交换机绑定队列,消费者从队列中取得消息.每次有消息,先发到交换机中,然后由交换机负责发送到它已知的队列中. 生产者代码: ...

  4. RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)

    1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...

  5. RabbitMQ详解(三)------RabbitMQ的五种模式

    RabbitMQ详解(三)------RabbitMQ的五种模式 1.简单队列(模式) 上一篇文章末尾的实例给出的代码就是简单模式. 一个生产者对应一个消费者!!! pom.xml ​ 必须导入Rab ...

  6. RabbitMQ入门案例

    RabbitMQ入门案例 Rabbit 模式 https://www.rabbitmq.com/getstarted.html 实现步骤 构建一个 maven工程 导入 rabbitmq的依赖 启动 ...

  7. SpringBoot整合RabbitMQ实现六种工作模式

    RabbitMQ主要有六种种工作模式,本文整合SpringBoot分别介绍工作模式的实现. 前提概念 生产者 消息生产者或者发送者,使用P表示: 队列 消息从生产端发送到消费端,一定要通过队列转发,使 ...

  8. RabbitMQ入门-高效的Work模式

    扛不住的Hello World模式 上篇<RabbitMQ入门-从HelloWorld开始>介绍了RabbitMQ中最基本的Hello World模型.正如其名,Hello World模型 ...

  9. RabbitMQ入门-Topic模式

    上篇<RabbitMQ入门-Routing直连模式>我们介绍了可以定向发送消息,并可以根据自定义规则派发消息.看起来,这个Routing模式已经算灵活的了,但是,这还不够,我们还有更加多样 ...

随机推荐

  1. SSM框架整合系列——第一步

    环境: JDK8 idea2018.2 maven3.5 spring和springMVC是天然集成,所以只需要解决mybatis和spring的整合问题,重点整合mybatis和spring的两个东 ...

  2. 三、oneinstack

    一.介绍 oneinstack https://www.cnblogs.com/lxwphp/p/9231554.html

  3. 使用@Validated分组遇到的坑

    在使用@Validate注解分组校验时,如果指定分组,所有的需要验证的属性都必须添加指定分组才会校验 解决办法: 没有指明分组的属性都属于Default,所以分组接口继承Default就可以解决

  4. Spring Boot 构建电商基础秒杀项目 (五) 用户注册

    SpringBoot构建电商基础秒杀项目 学习笔记 UserService 添加 void register(UserModel userModel) throws BusinessException ...

  5. Java线程的创建方式三:Callable(四)

    一.Java实现多线程的三种方式 方式一:继承Thread类: public class Test extends Thread { public static void main(String[] ...

  6. DRF 版本 认证

    DRF的版本 版本控制是做什么用的, 我们为什么要用 首先我们要知道我们的版本是干嘛用的呢大家都知道我们开发项目是有多个版本的 当我们项目越来越更新~版本就越来越多我们不可能新的版本出了~以前旧的版本 ...

  7. 安卓Android基础第三天——数据库,ListView

    数据库介绍sqlite问:什么情况下使用数据库?答:有大量相似结构的数据需要存储的时候 数据库的创建定义一个类继承SqliteOpenHelpercontext:上下文name:数据库名字,如&quo ...

  8. Spring02-注入和注解方式操作

    一. 依赖注入 测试类:Person.java 创建配置文件:applicationContext-injection.xml 创建测试代码:InjectionTest.java 1. set方法注入 ...

  9. 搭建web定时任务管理平台

    需要安装mysql及gityum -y install git mysql-server 下载安装go官网:https://golang.org/dl/wget https://redirector. ...

  10. Codeforces Round #517 Div. 2/Div. 1

    \(n\)天没更博了,因为被膜你赛的毒瘤题虐哭了... 既然打了这次CF还是纪念一下. 看看NOIP之前,接下来几场的时间都不好.这应该是最后一场CF了,差\(4\)分上紫也是一个遗憾吧. A 给一个 ...