使用两个线程导致 JavaFX 崩溃

Using two threads causes JavaFX to crash

我需要使用两个线程将两个不同的字符附加到同一个 JavaFX TextArea。我可以让一个工作,但是当我添加第二个线程时,它会因一些非常长的异常而中断。我做错了什么?

我查看了这个问题以寻求指导,它让我在一个线程上工作,但不是两个:

package application;
    

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;



public class Main extends Application {
    
    
    @Override
    public void start(Stage primaryStage) {
        
        try {
            BorderPane root = new BorderPane();
            TextArea textArea = new TextArea();
            textArea.setWrapText(true);
            root.setCenter(textArea);
            textArea.setText("");
            
            new Thread(() -> PrintChar(textArea, 'a', 100)).start();
            new Thread(() -> PrintChar(textArea, 'b', 100)).start();
                    
            
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
    private void PrintChar(TextArea textArea, char letter, int numb)
    {
        for(int i = 0; i < numb; ++i)
        {
            textArea.appendText(letter + "");
        }
    }
}

您不需要为此任务使用两个线程。您可以简单地按顺序调用 PrintChar 方法:

PrintChar(textArea, 'a', 100);
PrintChar(textArea, 'b', 100);

使用它会使 textArea 输出看起来像这样,每个输出 100 个:

aaaaaa.....bbbbbb.....


但是,如果您“想要”像这样使用两个线程:

new Thread(() -> PrintChar(textArea, 'a', 100)).start();
new Thread(() -> PrintChar(textArea, 'b', 100)).start();

然后您可以通过使用 Platform.runLater 安排 UI 更改,例如包围与 javafx 组件交互的代码,如下所示:

Platform.runLater(() -> {
    textArea.appendText(letter + "");
});

这将导致 textArea 被两个线程混合更改,看起来像这样(如果不采取额外步骤,您将无法控制执行顺序):

bbaaabbbbabbbaaaaa.....


如果你想使用线程,但也使用同步,那么它与完全不使用线程没有真正的区别(至少在你的场景中),但是,你可以这样做:

private synchronized void PrintChar(TextArea textArea, char letter, int numb)
{
    for(int i = 0; i < numb; ++i)
    {
        //We still need to wrap the UI code, because other methods from other threads could still interact with the UI and cause issues
        Platform.runLater(() -> {
            textArea.appendText(letter + "");
        });
    }
}

输出看起来像这样,每个顺序 100 个:

aaaaaa.....bbbbbb.....