【问题标题】:Make JavaFX application thread wait for another Thread to finish使 JavaFX 应用程序线程等待另一个线程完成
【发布时间】:2015-04-22 14:16:48
【问题描述】:

我正在我的 UI 线程中调用一个方法。在此方法中创建了一个新线程。我需要 UI 线程等到这个新线程完成,因为我需要这个线程的结果来继续 UI 线程中的方法。但我不想在等待时冻结 UI。有什么方法可以让 UI 线程在不忙于等待的情况下等待?

【问题讨论】:

  • 如果 UI 线程等待,则 UI 被冻结:这两个短语的含义完全相同。为什么要让 UI 线程“等待”?你能解释更多你真正想要达到的目标吗?
  • 我正在处理的应用程序没有设置为多线程,所以 UI 线程总是在做所有的工作。有一个类充当对服务器的所有调用的瓶颈,我需要向该类添加多线程。但是,我无法访问调用此瓶颈类的对象。
  • 对不起,这没有意义。仅使用我在答案中显示的方法有什么问题?
  • 我无法返回触发创建线程的调用堆栈。我想要的是 UI 线程在线程完成后继续创建线程的方法中的代码。
  • 为什么?对于您要解决的任何问题,这都是错误的解决方案。如果您阻止 UI 线程,则 UI 必然会变得无响应。是什么让您认为您需要这样做?

标签: java multithreading javafx


【解决方案1】:

您不应该让 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 元素与瓶颈类调用在同一范围内的类中编写此代码,这确实是理想的。不幸的是,这种情况并非如此。我无法向处理瓶颈类中方法调用的类添加代码。
【解决方案2】:

当线程完成时,只需调用一个通知 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 应用程序线程上。这样做,您使用的任何数据都将设置在一个线程中并从另一个线程访问,因此您需要(稍微)小心以确保您访问实时值。假设您要更新 UI,使用javafx.concurrent API 会容易得多。
  • @James_D 我知道,我认为这与实际问题是分开的。我已经编辑了我的答案,以包括在应用程序线程上更新 UI 的基础知识。
  • 是的,很难知道,因为 OP 没有解释为什么他希望 FX 应用程序线程“等待”...问题属于 this category
  • @James_D 确实如此。也让我想起了this
  • 我明白了。但是,如果我实现这一点,我将无法实现我想要的。哪个返回到触发创建线程的调用堆栈,结果。
猜你喜欢
  • 2016-08-17
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多