如何在Java中正确使用wait()和notify()? (HiveMQ客户端)

时间:2019-06-16 23:10:24

标签: java multithreading mqtt hivemq

我正在使用HiveMQ Client(Java中的MQTT开源实现)编写程序,其中涉及使用两个多线程客户端。一个客户端被指定为发布者,另一个客户端被指定为订阅者(我知道我可以让同一客户端同时发布和订阅)。我正在尝试设计一个测试,其中发布者向客户端发送100条消息。目的是确定发送和接收所有消息所花费的时间。我意识到,如果我想确定接收消息要花费多长时间,则需要让订阅线程等待发布线程准备好发送消息。我决定使用wait()和notify(),但似乎无法正确实现。我知道您需要使用与尝试相同的对象,但是我无法获得正确的设计。我在代码中为两个客户端的两个run方法添加了狙击手。 CommonThread.java实际上不是线程,并且我没有运行它,但是我试图在类之间使用它,以便能够wait()和notify(),但是我丢失了一些东西。

HiveMQ:

https://github.com/hivemq/hivemq-community-edition

https://github.com/hivemq/hivemq-mqtt-client

SubMainThread.java:

public void run() {

    // Creates the client object using Blocking API 

     Mqtt5BlockingClient subscriber = Mqtt5Client.builder()
    .identifier(UUID.randomUUID().toString()) // the unique identifier of the MQTT client. The ID is randomly generated between 
    .serverHost("localhost")  // the host name or IP address of the MQTT server. Kept it localhost for testing. localhost is default if not specified.
    .serverPort(1883)  // specifies the port of the server
    .addConnectedListener(context -> ClientConnectionRetreiver.printConnected("Subscriber1"))        // prints a string that the client is connected
    .addDisconnectedListener(context -> ClientConnectionRetreiver.printDisconnected("Subscriber1"))  // prints a string that the client is disconnected
    .buildBlocking();  // creates the client builder                
    subscriber.connect();  // connects the client
    ClientConnectionRetreiver.getConnectionInfo(subscriber);   // gets connection info

    try {
        Mqtt5Publishes receivingClient1 = subscriber.publishes(MqttGlobalPublishFilter.ALL);  // creates a "publishes" instance thats used to queue incoming messages                                                                   // .ALL - filters all incoming Publish messages     

        subscriber.subscribeWith()   
        .topicFilter(subscriberTopic) 
        .qos(MqttQos.EXACTLY_ONCE)
        .send(); 

        PubSubUtility.printSubscribing("Subscriber1"); 


        System.out.println("Publisher ready to send: " + PubMainThread.readyToSend);

        x.threadCondWait();    // <<<<< HOW TO MAKE THIS WORK 
        System.out.println("Back to the normal execution flow :P");


        startTime = System.currentTimeMillis();
        System.out.println("Timer started");

        for (int i = 1; i <= messageNum; i++) {  
            Mqtt5Publish receivedMessage = receivingClient1.receive(MESSAGEWAITTIME,TimeUnit.SECONDS).get(); // receives the message using the "publishes" instance waiting up to 5 minutes                                                                         // .get() returns the object if available or throws a NoSuchElementException 
            PubSubUtility.convertMessage(receivedMessage);  // Converts a Mqtt5Publish instance to string and prints 
            }   

        endTime = System.currentTimeMillis();

        finalTime = endTime - startTime;
        System.out.println( finalTime + PubMainThread.finalTime + " milliseconds");
        finalSecTime = TimeUnit.MILLISECONDS.toSeconds(finalTime);

        System.out.println(finalSecTime + PubMainThread.finalSecTime);
        }   

    catch (InterruptedException e) {    // Catches interruptions in the thread 
        LOGGER.log(Level.SEVERE, "The thread was interrupted while waiting for a message to be received", e);
        }

    catch (NoSuchElementException e){
        System.out.println("There are no received messages");   // Handles when a publish instance has no messages 
        }

    subscriber.disconnect();  

    }

PubMainThread.java:

public void run() {

    // Creates the client object using Blocking API 

    Mqtt5BlockingClient publisher = Mqtt5Client.builder()
    .identifier(UUID.randomUUID().toString()) // the unique identifier of the MQTT client. The ID is randomly generated between 
    .serverHost("localhost")  // the host name or IP address of the MQTT server. Kept it localhost for testing. localhost is default if not specified.
    .serverPort(1883)  // specifies the port of the server
    .addConnectedListener(context -> ClientConnectionRetreiver.printConnected("Publisher1"))         // prints a string that the client is connected
    .addDisconnectedListener(context -> ClientConnectionRetreiver.printDisconnected("Publisher1"))  // prints a string that the client is disconnected
    .buildBlocking();  // creates the client builder                
    publisher.connect();  // connects the client
    ClientConnectionRetreiver.getConnectionInfo(publisher);   // gets connection info

    PubSubUtility.printPublising("Publisher1");
    readyToSend = true; 
    x.threadCondNotify();        <<<<< HOW TO MAKE THIS WORK 
    // Think about making the PubClient Thread sleep for a short while so its not too ahead of the client
    startTime = System.currentTimeMillis();

        for (int i = 1; i <= messageNum; i++) { 
             publisher.publishWith()    
             .topic(publisherTopic)   // publishes to the specified topic
             .qos(MqttQos.EXACTLY_ONCE)  
             .payload(convertedMessage)  // the contents of the message 
             .send();
        }

    endTime = System.currentTimeMillis();
    finalTime = endTime - startTime;    
    finalSecTime = TimeUnit.MILLISECONDS.toSeconds(finalTime);

    PubSubUtility.printNumOfPublished("Publisher1", messageNum);    


    publisher.disconnect();  
    }

公共类CommonThread {

private static final Logger LOGGER = Logger.getLogger(SubMainThread.class.getName());  // Creates a logger instance 


public synchronized void threadCondNotify() {
    notify();
    System.out.println("Notified other thread");
}

public synchronized void threadCondWait() {

    try {       
        while (PubMainThread.readyToSend != true) {
        System.out.println("Waiting for another thread....");
        wait();
        }
    }

    catch (InterruptedException e) {
        LOGGER.log(Level.SEVERE, "The thread was interrupted while waiting for another thread", e);
    }
    }

}

1 个答案:

答案 0 :(得分:-1)

在Sender中(省略了一些详细信息的粗糙Java代码):

//package statement and imports here

class Sender extends Thread {
    public static final Boolean x= new Boolean(true); 

    public void run() {
        //initialize here
        synchronized(x) {
            x.notify();
        }
        //send messages here
    }
}

在Receiver中(在发送方之前开始):

//package statement and imports here

class Receiver extends Thread {

    public void run() {
        //initialize here
        synchronized(Sender.x) {
            Sender.x.wait(); //blocks till Sender.x.notify()
        }
        Date start= new Date();
        //receive messages here
        Date end= new Date();
        int duration_milliseconds= end.getTime()-start.getTime();
    }
}

也许您必须添加

try{ /* code here */ } catch (InterruptedException e) {}

随时讨论直接使用notify()和wait()的意义和废话,尤其是在具有扩展并发库的Java版本中...