在 java 中另一个线程处于 运行 时继续执行一个线程

Continue executing a thread while another thread is running in java

tl,博士;

我有一个创建另一个class对象的GUI线程(秒class已经实现了Runnable,但是这里我们不执行run()方法,相反,我们调用一个普通方法)并调用一个方法。在该方法中,再次调用第一个线程(当前线程)(在 LCD 上显示某事),然后将一些数据发送到 Internet,并等待 3 秒以等待服务器响应。问题是信息在 3 秒后打印出来。我知道 stackprogram counter,但我想知道是否还有其他选择可以完成我的工作。


我有运行 3 个线程的 main 方法(简而言之,我只写了必要的代码。如果需要,告诉我添加更多):

public static void main(String[] args) throws UnknownHostException, InterruptedException {
        
        
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    GUI.getInstance().setVisible(true); //GUI is singleton, using swing and JFrame
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        MQTTConnection.getInstance().tryToConnect(); //It's the connection class, which has a thread (the thread is handled by a library that keeps the connection alive. I have no threads there) and is a singleton too.

        Thread t1 = new Thread(new SendDataThread()); //A thread which sends some data every 20 seconds.
        t1.start();
    }

在 SendDataThread 中,我有一个函数可以创建一些随机数据并发送它们(使用 MQTTConnection class)。

这是SendDataThread:

public class SendDataThread implements Runnable {
    
    public void sendLog() {
        boolean serverOnline = false;
        StringBuilder data = new StringBuilder();
        data.append(createData());
        GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
        
        if(MQTTConnection.getInstance().publishLog(MQTTConnection.getInstance().MQTT_PUBLISH_ESP_SEND_LOG, data.toString())) //This line has a 3 second timeout. If the server doesn't respond, it will return false. I've added the 3 seconds timeout too. Please continue reading.
            serverOnline = true;
        
        if(serverOnline)
            GUI.getInstance().printOK("Server Submitted"); //Prints in GREEN
        else
            GUI.getInstance().printProblem("Check your connection!"); //Prints in RED
        
        GUI.getInstance().printNeutral("-------------------------------------------------");
    }
    
    @Override
    public void run() {
        while(true) {
            sendLog();
            try {
                Thread.sleep(20000); //sleeps 20 about seconds
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
//.....
}

这是3秒超时方法,在MQTTConnection:

    boolean publishLog(String topic, String data){
        mqtt_responds = false;
        publish(topic, data);
        System.out.println("MQTT is connected");
        long lastTime = System.currentTimeMillis();
        while(System.currentTimeMillis() - lastTime < callback_timeout) {
            if(mqtt_responds){
                mqtt_responds = false;
                System.out.println("Server submitted");
                return true;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Timeout");
        return false;
    }

到目前为止,一切正常。问题开始于我在 GUI class 中有一个按钮,用户可以手动发送随机日志:

        JButton sendLogBtn = new JButton("Send Log");
        sendLogBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SendDataThread sdt = new SendDataThread();
                sdt.sendLog();
            }
        });
        sendLogBtn.setBounds(10, 331, 89, 23);
        panel.add(sendLogBtn);

这个按钮创建一个SendDataThread对象并调用sendLog()方法。问题发生在这里:在调用 sendLog() 之后,sendLog(),再次调用此 GUI 线程:

-->     GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`

但是3秒后打印日志(sendLog()方法完成后,超时!)

我该如何解决这个问题?

在按钮的 actionPerformed 中,您正在呼叫 sendLogsendLog 完全按照你说的做,即报告一些日志并等待大约 3 秒(假设 callback_timeout 大约等于 3000)。

要解决此问题,您需要确保 3 秒阻塞不在 EDT 上,还要确保日志在 EDT 上 posted。

作为快速解决方法,您可以执行以下操作:

sendLogBtn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        new Thread(() -> new SendDataThread().sendLog()).start();
    }
});

然后,一如既往,post 您在 EDT 中的日志,例如:

SwingUtilities.invokeLater(() -> GUI.getInstance().printNeutral(...));

SwingUtilities.invokeLater(() -> GUI.getInstance().printProblem(...));

SwingUtilities.invokeLater(() -> GUI.getInstance().printOk(...));

至于 ,我不太明白你在问什么,但我应该说(据我所知)EDT 是一个 Thread,其中所有的 Swing 代码正在(并且应该)post 执行。这样 Swing 代码就不必是 synchronized,因为所有与 GUI 相关的东西都是按顺序执行的(在 EDT 上)。据我所知,例如 AWT 并不打算成为单线程的。然而,Swing 是单线程的。