JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
RRPC指的是调用该接口向指定设备发送请求消息,并同步返回响应
在物联网场景下,如果想要做到Java服务与硬件同步通信的效果,那么一般会依赖MQTT来实现通信
比如Java服务向硬件发送请求,请求查询硬件相关信息
- Java服务和硬件要提前订阅对应的Topic
- Java服务先将消息发送到MQTT上(硬件订阅的Topic上)
- 硬件订阅Topic收到消息后进行消费,消费完再发送ack响应消息到MQTT上(Java服务订阅的Topic上)
在这个同步通信的过程中,Java服务发送完消息是需要等待直到ack响应的,那么这个过程在Java服务端该如何实现这种等待/唤醒的模式呢?
本文就结合JUC组件来实现Java与硬件(通过MQTT)同步通信的组件
(为了简化流程,我们代码中使用阻塞队列代替MQTT)
整体流程
整体流程可以想象成远程调用的流程,只不过消费端是硬件,并且它们是通过MQTT转发消息来做到通信的
举例:把Java服务当作A端、把硬件当作B端,它们需要提前订阅MQTT上的topic
- A端发送消息到B端订阅的Topic上,并进入等待状态(等待收到响应后唤醒)
- B端订阅Topic收到消息后消费,响应并发送到A端订阅的Topic
- A端订阅Topic的线程收到消息后进行解析,如果消息是当前节点需要处理的,则唤醒A端发送消息的线程
在这个过程中主要涉及四个线程:
- A端发送消息的业务线程
- B端接收消息并响应的线程
- A端接收消息并唤醒的业务线程
- A端定时删除超时的任务,防止内存泄漏
由于MQTT中间件太大,为了简化流程,我使用LinkedBlockingQueue进行模拟MQTT通信
/**
* 模拟MQTT通信时 A端 接收消息的 Topic
*/
private static final LinkedBlockingQueue<String> mqttTopicA = new LinkedBlockingQueue<>();
/**
* 模拟MQTT通信时 B端 接收消息的 Topic
*/
private static final LinkedBlockingQueue<String> mqttTopicB = new LinkedBlockingQueue<>();
流程代码:
- 先启动B端消费线程
- 在启动A端接收线程
- 在模拟A端业务线程发送消息
public static void main(String[] args) {
//1.开启消费线程 模拟B端消费消息
Thread bConsumerThread = new Thread(() -> {
while (true) {
//获取消息
String msgId = null;
try {
msgId = mqttTopicB.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//消费..
System.out.println("2." + Thread.currentThread().getName() + "消费消息:" + msgId);
//消费完响应
mqttTopicA.offer(msgId);
}
}, "B端消费线程");
bConsumerThread.setDaemon(true);
bConsumerThread.start();
//2.开启接收线程 模拟A端接收消息
Thread aReceivedThread = new Thread(() -> {
while (true) {
//获取消息
String msgId = null;
try {