JavaFX 多线程

JavaFX Multithreading

我的 JavaFx 应用程序遇到了一个问题。

前言:我不想只针对我的应用程序,而是想概括一下,以便像我这样的人对类似情况有所了解。

背景:使用fxml文件和多线程概念实现Javafx应用程序。

总结:我尝试制作一个基本上使用多线程来完成一些任务的应用程序,一旦多线程完成,它将依次移动到另一个任务。在执行多线程时,主 GUI 冻结。

我做了什么,

//This is Main class

Parent Root  -> defined on top
public Parent createContent(){
 try{
  root =  FXMLLoader.load(getClass().getResource("Layout.fxml"));
  }catch { .....}
 }

 public void start(){
    stage.setScene(new Scene(createContent()));
    Task<Void> task = new Task<Void>() {
            @Override
            public Void call() throws Exception {
                Thread.sleep(1000);
                return null ;
            }
        };
      task.setOnSucceeded(event->{
            stage.show();
        });
        new Thread(task).run();
  }
  public static void main(String[] args) {
        launch(args);
    }
// This is inside the controller on button click event
@FXML
private void start(ActionEvent event) { <---- This one is button click event
   Thread t1 = new Thread(new Mul());
    t1.start();
    Thread t2 = new Thread (new Mul());
    t2.start();
}

 // Finally 
public class Mul implements Runnable {
  public void type() {
    for (int a = 0; a < 200000; a++) {
        System.out.println( Thread.currentThread().getName()+ " says " + a);
    }
   }
    @Override
   public void run() {
     type();
   }

}

现在,这是结果。 如果我只是从控制器启动线程,那么当线程在后台 运行 时,我的主应用程序不会冻结。但是,由于应用程序按顺序运行,即下一步仅在线程完成工作时才起作用

我可以使用 t1.join() 和 t2.join() ,但是这样做会冻结我的主应用程序(这里的主应用程序是主 GUI)并且我无法继续它直到线程完成。

最佳解决方案是什么,这样我就可以在不阻塞主应用程序的情况下使用多线程,或者我在这里做错了什么? (info我通过遵循 Stack overflow 和 google 的不同建议得出了这个解决方案)

为什么不做

Task<Void> task = new Task<Void>() {
    @Override
    public Void call() {
        Mul m1 = new Mul();
        m1.run();
        Mul m2 = new Mul();
        m2.run();
        return null ;
    }
};
new Thread(task).start();

如果你真的想要 "chain" 不同的任务,从另一个的 onSucceeded 处理程序中调用一个:

Task<Void> task1 = new Task<Void>() {
    @Override
    public Void call() {
        new Mul().run();
        return null ;
    }
};

Task <Void> task2 = new Task<Void>() {
    @Override
    public Void call() {
        new Mul().run();
        return null ;
    }
};

task1.setOnSucceeded(e -> new Thread(task2).start());

new Thread(task1).start();

显然,如果您将 Mul 设为 Task 子类而不是 Runnable,这会更清晰,并且最好将 Executor 与守护线程等一起使用,但这应该会给你灵感。