如何停止java方法,直到它收到来自MQTT代理的消息
我有一个包含2个方法的类,每个方法分别发布和订阅一个公共MQTT代理如何停止java方法,直到它收到来自MQTT代理的消息,java,mqtt,paho,Java,Mqtt,Paho,我有一个包含2个方法的类,每个方法分别发布和订阅一个公共MQTT代理 public class operations{ public void fetch(){ // do something mqttConn.mqttSubscriberFetch(MQTTtopic); // do something } public void store(){ // do something mqttConn.mqttSubscribe
public class operations{
public void fetch(){
// do something
mqttConn.mqttSubscriberFetch(MQTTtopic);
// do something
}
public void store(){
// do something
mqttConn.mqttSubscriberStore(MQTTtopic);
// do something
}
}
方法获取的MQTT方法如下所示:
public class mqttConnectionFetch implements MqttCallback{
MqttClient client;
String topic;
public mqttConnectionFetch() {
}
public void mqttSubscriberFetch(String topic) {
final String MQTT_BROKER = "tcp://localhost:1883" ;
final String CLIENT_ID = "fetch";
try {
client = new MqttClient(MQTT_BROKER, CLIENT_ID);
client.connect();
client.setCallback(this);
client.subscribe(topic);
MqttMessage message = new MqttMessage();
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void connectionLost(Throwable cause) {
// TODO Auto-generated method stub
}
@Override
public void messageArrived(String topic, MqttMessage message)
throws Exception {
System.out.println("the message received is "+message);
if(message.toString().equals("Processed")) {
MqttPublisherFetch("Processed", "operations/fetch");
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// TODO Auto-generated method stub
}
public void MqttPublisherFetch(String message, String topic) {
final String MQTT_BROKER = "tcp://localhost:1883" ;
final String CLIENT_ID = "store";
try {
client = new MqttClient(MQTT_BROKER, CLIENT_ID);
client.connect();
createMqttMessage(message,topic);
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
private void createMqttMessage(String message, String topic) throws MqttException {
MqttMessage publishMessage = new MqttMessage();
publishMessage.setPayload(message.getBytes());
client.publish(topic, publishMessage);
}
}
现在,我正试图实现这样一种功能,即每当我的fetch方法订阅一个主题时,如果来自代理的消息处于“处理”状态,它就应该处于等待状态。而存储方法应该正常工作。当收到的消息被“处理”后,提取应该再次开始工作
我用普通的java wait()和start()进行了尝试,但没有得到所需的输出。
有人能帮我解开这个谜团吗?据我所知,存储方法由几个步骤组成。其中一个步骤是通过MQTT发送消息并等待响应。从
store
方法的客户机的角度来看,它是同步的,即客户机只有在整个处理(包括通过MQTT异步发送/接收)完成后才会接收响应
这里要解决的是一个经典问题,当一个线程需要等待另一个线程中发生某种情况时。有很多方法可以实现这一点,只需检查中提出的选项数量
最简单的方法是使用倒计时闩锁
。我将使用fetch
方法,因为这是您提供代码的方法
首先,您需要修改mqttSubscriberFetch
以创建内部CountDownLatch
对象:
private CountDownLatch processingFinishedLatch;
public void mqttSubscriberFetch(String topic) {
final String MQTT_BROKER = "tcp://localhost:1883" ;
final String CLIENT_ID = "fetch";
try {
client = new MqttClient(MQTT_BROKER, CLIENT_ID);
client.connect();
client.setCallback(this);
client.subscribe(topic);
MqttMessage message = new MqttMessage();
processingFinishedLatch = new CountDownLatch(1);
} catch (MqttException e) {
e.printStackTrace();
}
}
然后您需要在消息接收回调中触发此信号:
@Override
public void messageArrived(String topic, MqttMessage message)
throws Exception {
System.out.println("the message received is "+message);
if(message.toString().equals("Processed")) {
MqttPublisherFetch("Processed", "operations/fetch");
this.processingFinishedLatch.countDown();
}
}
您还需要为mqttConnectionFetch
的客户端提供一种等待闩锁变为零的方法:
void waitForProcessingToFinish() throws InterruptedException {
this.processingFinishedLatch.await();
}
fetch
方法应该这样使用它:
public void fetch(){
// do something
mqttConn.mqttSubscriberFetch(MQTTtopic);
// do everything that is needed to initiate processing
mqttConn.waitForProcessingToFinish()
// do something
}
执行fetch
的线程将在waitForProcessingToFinish
中等待,直到闩锁达到零,并在相应的消息出现时发生
这种方法可以很容易地修改,以便在消息从未出现时解决问题。只需使用:
fetch
应该检查返回的值,如果发生超时,可能会将错误返回给调用方
请注意,此解决方案有一个缺点,即正在处理fetch
的线程将一直处于繁忙状态。如果这是线程池中用于处理传入HTTP请求的线程,则可能会限制服务器可以并发处理的请求数。
有一些方法可以缓解这种情况,例如,或。这个问题的实际解决方案在很大程度上取决于您用于REST API实现的技术。为什么不简单地使用观察者/监听器模式,并在状态更改通知时调用适当的方法呢?首先,在同一进程中运行多个MQTT客户机几乎没有什么好的理由,一个对发布和订阅都很好我不确定我是否理解你想要什么。。。以书面形式获取客户机订阅MQTT服务器并等待,只有当它从代理接收到消息时才会唤醒。如果它接收到来自代理的“正在处理”消息,它可以忽略/记录它并返回等待(这是它将要做的);如果它收到一条“已处理”的消息,它可以处理它,然后返回等待下一条消息。您希望如何改变这种行为?如果远程客户端关闭,而您从未收到响应,又会发生什么情况?看起来您正在解决一些问题,但正如前面指出的那样,这已经是一种非常低效的方式。你能描述一下你为什么需要这样做吗?基本上你能描述你试图解决的更高层次的问题吗。
boolean waitForProcessingToFinish(long timeout,
TimeUnit unit) throws InterruptedException {
return this.processingFinishedLatch.await();
}