让JavaFX应用程序线程等待另一个线程完成

6
我正在UI线程中调用一个方法。在这个方法内部创建了一个新线程。我需要UI线程等待直到新线程完成,因为我需要该线程的结果来继续UI线程中的方法。但我不想在等待时使UI冻结。有没有一些方法可以让UI线程等待而不是忙等待?

1
如果UI线程等待,UI将被冻结: 这两个短语的意思完全相同。为什么要让UI线程“等待”?您能更详细地解释一下您实际想要实现的内容吗? - James_D
我正在开发的应用程序没有设置多线程,因此UI线程始终在处理所有工作。有一个类充当所有对服务器调用的瓶颈,我需要为该类添加多线程支持。但是,我无法访问调用此瓶颈类的对象。 - Jupiter
我将无法返回到触发创建线程的调用堆栈。我的意愿是UI线程在线程完成后继续执行创建线程的方法中的代码。 - Jupiter
我需要这样做是因为我无法访问更新UI的逻辑,该逻辑位于充当瓶颈的类中。不幸的是,我无法修改更新UI的代码以允许我在进程完成后调用它,因此我必须从调用堆栈返回结果。 - Jupiter
不需要。我发布的解决方案已经涵盖了所有内容。请查看更新后的答案,其中我已经详细说明了。 (你为什么不试一下呢...?) - James_D
显示剩余3条评论
2个回答

12

永远不要让FX应用程序线程等待;这会冻结UI并使其无响应,无法处理用户操作和呈现任何内容到屏幕。

如果你想在长时间运行的进程完成后更新UI,请使用javafx.concurrent.Task API。例如:

someButton.setOnAction( event -> {

    Task<SomeKindOfResult> task = new Task<SomeKindOfResult>() {
        @Override
        public SomeKindOfResult call() {
            // process long-running computation, data retrieval, etc...

            SomeKindOfResult result = ... ; // result of computation
            return result ;
        }
    };

    task.setOnSucceeded(e -> {
        SomeKindOfResult result = task.getValue();
        // update UI with result
    });

    new Thread(task).start();
});

显然需要替换SomeKindOfResult为表示长时间运行过程结果的任何数据类型。

请注意onSucceeded块中的代码:

  1. 必须在任务完成后执行
  2. 可以通过task.getValue()访问后台任务执行的结果
  3. 本质上处于启动任务的地方相同的范围内,因此可以访问所有UI元素等。

因此,这种解决方案可以做到等待任务完成时能做的任何事情,但同时不会阻塞UI线程。


如果我可以在一个类中编写此代码,其中UI元素与瓶颈类的调用处于相同的作用域,那将是非常理想的。不幸的是,情况并非如此。我无法向处理对瓶颈类方法调用的类中添加代码。 - Jupiter

1

只需调用一个方法,当线程完成时通知GUI。类似于这样:

class GUI{

   public void buttonPressed(){
      new MyThread().start();
   }

   public void notifyGui(){
      //thread has finished!

      //update the GUI on the Application Thread
      Platform.runLater(updateGuiRunnable)
   }

   class MyThread extends Thread{
      public void run(){
         //long-running task

         notifyGui();
      }
   }
}

但请注意,使用此代码,“notifyGui()”将从后台线程调用,因此它无法直接更新UI:任何UI更新必须在FX Application线程上安排。并且这样做,您使用的任何数据都将在一个线程中设置并从另一个线程访问,因此您需要(有点)小心以确保您访问实时值。假设您要更新UI,最好使用“javafx.concurrent” API。 - James_D
很难知道为什么原帖作者想要FX应用程序线程“等待”,因为他没有解释... 这个问题属于“XY问题”类别。 - James_D
@James_D 确实如此。这让我想起了这个 - Kevin Workman
我明白了。然而,如果我实现这个,我将无法达到我想要的目标,即返回触发线程创建并带有结果的调用堆栈。 - Jupiter
@Jupiter 嗯,不行。你不能两全其美。你要么等待线程完成,要么让线程在完成时发出信号通知你。 - Kevin Workman
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接