org.eclipse.paho.client.mqttv3 同步Client 发布订阅线程为同一个时,将永久阻塞的问题

org.eclipse.paho.client.mqttv3 同步Client 发布订阅线程为同一个时,将永久阻塞的问题

使用MQTT版本为:

<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.5</version>
</dependency>

问题复现

使用 Flux 改造MQTT Client 时,又如下业务行为即订阅某一主题A,当主题A中消息到达时根据A的内容发布主题B消息。

getClient().subscribeTopic(MqttTopic.newTopic(topic, Qos._0, Direction.Sub))
        .doOnNext(mqttMessage -> System.out.println("sub 中的线程 " + Thread.currentThread().getName()))
//                .publishOn(publishSchedule)
        .map(requestToResponse)
        .map(responseMessage -> Tuples.of(responseMessage, singletonClient.publish(responseMessage)))
        .subscribe(tuple -> {
            System.out.println("--------------------------------------------------");
            System.out.println("消息已回复 【"+ (tuple.getT2() ? "成功" : "失败") +"】");
            System.out.println("消息体为 " + tuple.getT1().getMessage().toString());
            System.out.println("--------------------------------------------------");
        });

此时 客户端发布将永远保持阻塞。

问题排查

jps查询当前所有Java 程序 pid 。

jstack -l 1736查看线程 dump。

结果如下,其中在问题发生前线程状态为:

"MQTT Call: sceneServer-test-client-78afe" #16 prio=5 os_prio=0 tid=0x000000002989c000 nid=0x5b20 in Object.wait() [0x000000002b30f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000071a1bd478> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:502)
        at org.eclipse.paho.client.mqttv3.internal.CommsCallback.run(CommsCallback.java:181)
        - locked <0x000000071a1bd478> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

问题发生后线程状态为:

"MQTT Call: sceneServer-test-client-78afe" #16 prio=5 os_prio=0 tid=0x000000002989c000 nid=0x5b20 in Object.wait() [0x000000002b30d000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000071d139730> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:502)
        at org.eclipse.paho.client.mqttv3.internal.Token.waitForResponse(Token.java:143)
        - locked <0x000000071d139730> (a java.lang.Object)
        at org.eclipse.paho.client.mqttv3.internal.Token.waitForCompletion(Token.java:108)
        at org.eclipse.paho.client.mqttv3.MqttToken.waitForCompletion(MqttToken.java:67)
        at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:570)
        at org.eclipse.paho.client.mqttv3.MqttClient.publish(MqttClient.java:562)
        at com.whb.util.mqtt.MqttClient.publish(MqttClient.java:141)

由此可见,线程阻塞在 org.eclipse.paho.client.mqttv3.internal.Token.waitForResponse(Token.java:143)方法中,通过调试查看该方法发现:

方法中 responseLock.wait(); 使线程开始等待,并通过同类下的: protected void notifyComplete() 方法唤醒线程。

通过断点调试可以发现,调用 protected void notifyComplete() 的线程与订阅的线程为同一线程,若客户端订阅线程为A发布线程也为A时,将导致线程阻塞。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0 jar 是一个基于 Eclipse PahoMQTT 客户端库。MQTT 是一种轻量级的通讯协议,广泛应用于物联网和机器间通信领域。该库提供了在 Java 程序中使用 MQTT 协议进行消息传输的功能。 通过引入 org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0 jar,我们可以在 Java 程序中使用 MQTT 客户端功能。它提供了一系列的类和方法,用于连接到 MQTT 服务器、发布和订阅消息、处理消息回调等等。 使用该库,我们可以轻松建立 MQTT 连接并与其他设备进行通信。我们可以创建 MQTT 客户端对象,通过设置连接参数(如 MQTT 服务器地址、端口号、用户名、密码等)来连接到 MQTT 服务器。连接成功后,我们可以发布消息到指定的 MQTT 主题(topic),也可以订阅感兴趣的主题,接收其他设备发布的消息。 这个库还提供了消息的质量等级(QoS)控制机制,可以确保消息的可靠性和传输质量。它支持三个不同的 QoS 等级:0 表示至多一次的传输,可能会有数据丢失;1 表示至少一次的传输,确保消息到达,但可能会重复传输;2 表示仅一次的传输,确保消息到达且仅传输一次。 总而言之,org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0 jar 提供了在 Java 程序中使用 MQTT 协议进行通信的功能,使我们可以轻松地连接到 MQTT 服务器、发布和订阅消息,并控制消息的质量等级。这使得我们能够更方便地构建物联网和其他机器间通信的应用程序。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值