Sve*_*els 5 java multithreading javafx
我正在编写一个应用程序(供个人使用),它允许我通过 USB 向 Arduino 发送字符串。
我写了这个方法来发送数据:
/**
* Sends the data to the Arduino.
* A new Thread is created for sending the data.
* A transmission cool-down is started before send() method can be used again.
* @param data the data to send to the Arduino
*/
public void send(String data) {
if (connected && !sending) {
// Set 'sending' to true so only 1 Thread can be active at a time
sending = true;
// Create a new thread for sending the data
Thread thread = new Thread(() -> {
// Send the data
PrintWriter output = new PrintWriter(chosenPort.getOutputStream());
output.print(data);
System.out.println("Data sended");
output.flush();
// Wait for the transmission cool-down and set 'sending' to false to allow for another Thread to send data
try { Thread.sleep(transmissionCoolDown); } catch (InterruptedException interruptedException) { interruptedException.printStackTrace(); }
sending = false;
System.out.println("cooldown is over");
});
thread.start();
}
}
Run Code Online (Sandbox Code Playgroud)
sending是一个布尔值,用于指示线程是否正在发送数据。这transmissionCooldown只是为了在再次发送数据之前强制执行特定的等待期。
这就是使用该方法的地方:
@FXML
private void sendClicked() {
// Only do something if a connection is active and an image is selected.
// Should be unnecessary since the send button is only enables when both are true.
if (connected && selectedIV.getImage() != null) {
if (!sending) {
// Save the original text of the send button and disable the disconnect button
String ogText = sendButton.getText();
System.out.println(ogText);
connectButton.setDisable(true);
// If the data has not been saved before, get the data by formatting the image
if (data == null) {
data = imgCon.toStringFormat(true);
}
ardComm.send(data);
// While the ArduinoCommunicator is busy sending, change the text on the send button to indicate the data is being transmitted
sendButton.setText("busy");
while (ardComm.isSending()) {
}
// Restore the text on the send button
sendButton.setText(ogText);
connectButton.setDisable(false);
}
}
}
Run Code Online (Sandbox Code Playgroud)
sendButton是调用sendClicked()方法的 JavaFX 按钮,ardCom是包含该send()方法的类的实例。isSending()简单地返回 的发送属性,该属性ardCom在send()方法开始时设置为 true,并在 Thread 完成发送时设置为 false。
问题在于这段代码:
sendButton.setText("busy");
while (ardComm.isSending()) {
}
// Restore the text on the send button
sendButton.setText(ogText);
Run Code Online (Sandbox Code Playgroud)
我正在尝试将sendButton's text设置为 busy 以指示正在发送数据,然后循环直到数据传输完成(发送设置为 false)并以将sendButton背面的文本更改为原始文本来结束它. 我知道这可能不是实现这一目标的最佳方法,但我一直在玩,无法弄清楚为什么这不能按预期工作。
问题是由于某种原因,while 循环永远不会结束。
将 JavaFx 应用程序视为在单线程上运行的应用程序。
当该线程忙于运行长 while 循环 ( while (ardComm.isSending()) 时,它不会更新 gui。GUI 变得无响应(冻结)。
有关更多信息,请参阅在 JavaFX 应用程序线程上实现长时间运行的任务不可避免地会使应用程序 UI 无响应。
考虑监听更改事件而不是等待 JavaFx 应用程序线程:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
private Button sendButton;
@Override
public void start(Stage primaryStage) throws Exception{
ArdCom ardComm = new ArdCom();
sendButton = new Button("Send");
sendButton.setOnAction(event-> ardComm.send());
ardComm.isSending().addListener((observable, oldValue, newValue) -> {
if(newValue){
Platform.runLater (() ->sendButton.setText("Busy"));
}else{
Platform.runLater (() ->sendButton.setText("Send"));
}
});
AnchorPane root = new AnchorPane(sendButton);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class ArdCom {
private final ReadOnlyBooleanWrapper sending = new ReadOnlyBooleanWrapper(false);
void send() {//synchronize if accessed from multi thread
if (! sending.get() ) {
sending.set(true);
Thread thread = new Thread(() -> {
System.out.println("Send started");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
sending.set(false);
System.out.println("Send completed");
});
thread.start();
}
}
SimpleBooleanProperty isSending(){
return sending;
}
}
Run Code Online (Sandbox Code Playgroud)