gpt4 book ai didi

java线程立即更新UI

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:44 25 4
gpt4 key购买 nike

我有一个可视化计算几何算法的 javaFX 应用程序。算法的执行发生在另一个线程中,我们称之为 mainComputingThread。算法可以随时通过添加/删除/修改形状来更新 UI。所以代码看起来像:

//do some computaions (1)
updateUI();
//do some more calculations (2)

我想知道的是在 updateUI 方法中立即更新 UI 并阻止调用线程进一步运行(标记为 (2)),直到 UI 更新完成。

我想到了 boolean 守卫。所以代码可能看起来像:

updateUI(){
boolean guard = false;
Platform.runLater(new Runnable()
{
run(){
//do the actual update
guard = true;
}
});
while(guard==false);
}

我希望你明白我的意思。我真的很好奇这个问题是否有更好的解决方案...

最佳答案

简单方法:阻塞后台线程直到更新完成:

您需要在 FX 应用程序线程上更新 UI。通常,您通过将纯 Runnable 传递给 Platform.runLater(...) 来执行此操作。

如果你想在继续之前等待 ui 更新完成,而是创建一个 FutureTask并将其传递给 Platform.runLater(...)。然后你可以在 FutureTask 上调用 get(),它将阻塞直到任务完成:

private void updateUI() throws InterruptedException {

// actual work to update UI:
FutureTask<Void> updateUITask = new FutureTask(() -> {

// code to update UI...

}, /* return value from task: */ null);

// submit for execution on FX Application Thread:
Platform.runLater(updateUITask);

// block until work complete:
updateUITask.get();
}

这让 FutureTask 处理所有等待和通知的棘手工作:如果可能,最好为此类工作使用更高级别的 API。

如果愿意,您可以将其重构为实用方法,类似于 Dainesch 的回答:

public class FXUtils {

public static void runAndWait(Runnable run) throws InterruptedException {
FutureTask<Void> task = new FutureTask<>(run, null);
Platform.runLater(task);
task.get();
}
}

另一种方法:确保在任何帧渲染期间不消耗超过一个更新,如果更新挂起则阻塞后台线程

这是一种稍微不同的方法。创建一个容量为 1BlockingQueue 来保存更新 UI 的 Runnable。从您的后台线程,将 Runnable 提交到阻塞队列:因为阻塞队列最多可以容纳一个元素,所以如果一个元素已经挂起,这将阻塞。

要实际执行队列中的更新(并删除它们,以便添加更多更新),请使用 AnimationTimer。这看起来像:

private final BlockingQueue<Runnable> updateQueue = new ArrayBlockingQueue<>(1);

后台线程代码:

// do some computations...

// this will block while there are other updates pending:
updateQueue.put(() -> {
// code to update UI
// note this does not need to be explicitly executed on the FX application
// thread (no Platform.runLater()). The animation timer will take care of that
});

// do some more computations

创建定时器来消费更新:

AnimationTimer updateTimer = new AnimationTimer() {

@Override
public void handle(long timestamp) {
Runnable update = updateQueue.poll();
if (update != null) {
// note we are already on the FX Application Thread:
update.run();
}
}
};

updateTimer.start();

这基本上确保在任何时候都不会安排超过一个更新,后台线程会阻塞,直到消耗完所有待处理的更新。动画计时器检查(不阻塞)每个帧渲染上的未决更新,确保执行每个更新。这种方法的好处是您可以增加阻塞队列的大小,有效地保留待处理更新的缓冲区,同时仍然确保在任何单帧渲染期间不会消耗超过一个更新。如果偶尔有比其他计算花费更长的计算时间,这可能会有用;它使这些计算有机会在其他计算等待执行时进行计算。

关于java线程立即更新UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30569709/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com