JAVAFX:为什么等待游标需要一个新线程?

时间:2015-11-14 18:39:09

标签: java multithreading javafx threadpool

我明白为什么

 scene.setCursor(Cursor.WAIT);
 long task...
 scene.setCursor(Cursor.DEFAULT);

需要新线程;它适用于:

private void set_cursore_attesa(final Scene scene)
{
    Runnable r=new Runnable() {

        @Override
        public void run() {
             scene.setCursor(Cursor.WAIT);
        }
    };
    Thread t=new Thread(r);
    t.start();
}
private void set_cursore_normale(final Scene scene)
{
        Runnable r=new Runnable() {

        @Override
        public void run() {
             scene.setCursor(Cursor.DEFAULT);
        }
    };
    Thread t=new Thread(r);
    t.start();
}

in my function:
set_cursore_attesa(scene);
long task...
set_cursore_normale(scene);

为什么我不能使用相同的线程?    I:

  1. 将我的光标设置为WAIT(它进入GUI队列)
  2. 完成我的长任务......(它进入GUI队列,但我希望光标改变,即在队列中,它在此之前执行)
  3. 将光标重置为DEFAULT(在我的任务完成后)
  4. 那么,我的长任务不会进入MAIN队列?因为,如果它进入主队列,我预计它会在我首先插入队列的WAIT游标之后执行。 为什么会出现这种情况?

1 个答案:

答案 0 :(得分:7)

没有线程,您的代码正在FX应用程序线程上执行。这是(有效地)负责将UI呈现给屏幕并处理用户输入的线程。如果在此线程上执行长时间运行的任务,则会阻止FX应用程序线程的任何正常功能发生,直到长时间运行的任务完成。特别是,如果你这样做

scene.setCursor(Cursor.WAIT);
longRunningTask();
scene.setCursor(Cursor.DEFAULT);

然后按照您指定的顺序进行设置,但是在所有代码行完成之前,场景不会被重新呈现。因此,在代码完成之前,您永远不会看到对UI的任何更改 - 包括对光标的更改。下一次FX应用程序线程有机会渲染场景时,光标设置为Cursor.DEFAULT,您永远不会看到等待光标。

多线程和JavaFX有两个基本规则(相同的规则通常适用于大多数UI工具包):

  1. 对UI 的任何更改必须 在FX应用程序主题上执行
  2. 不应该在FX应用程序线程上执行长时间运行的进程(因为它们会使UI无响应)
  3. 所以你的解决方案实际上并不正确,因为你违反了这两个规则。你应该

    1. 将光标设置为FX Application Thread
    2. 上的WAIT
    3. 在后台线程上启动长时间运行的任务
    4. 任务完成后,在FX应用程序主题上将光标设置回DEFAULT
    5. 您可以使用Task

      执行此操作
      scene.setCursor(Cursor.WAIT);
      Task<Void> task = new Task<Void>() {
          @Override
          public Void call() {
              // long running task here...
              return null ;
          }
      };
      task.setOnSucceeded(e -> scene.setCursor(Cursor.DEFAULT));
      new Thread(task).start();