我有一个javaFX应用程序可视化计算几何算法.算法的执行发生在另一个线程中,让我们调用它mainComputingThread
.算法可以通过添加/删除/修改形状随时更新UI.所以代码看起来像:
//do some computaions (1)
updateUI();
//do some more calculations (2)
Run Code Online (Sandbox Code Playgroud)
我想知道的是在updateUI
方法中立即更新UI并阻止调用线程进一步运行(标记为(2))直到UI更新完成.
我想到了布尔警卫.所以代码可能看起来像:
updateUI(){
boolean guard = false;
Platform.runLater(new Runnable()
{
run(){
//do the actual update
guard = true;
}
});
while(guard==false);
}
Run Code Online (Sandbox Code Playgroud)
我希望你能明白我的意思.我真的好奇是否有更好的解决方案来解决这个问题...
简单方法:阻止后台线程直到更新完成:
您需要更新FX应用程序线程上的UI.通常,您可以通过传递平原来执行此Runnable
操作Platform.runLater(...)
.
如果您想在继续之前等待ui更新完成,请创建一个FutureTask
并将其传递给Platform.runLater(...)
.然后,你可以调用get()
的FutureTask
,这将阻塞,直到任务完成:
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();
}
Run Code Online (Sandbox Code Playgroud)
这使得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();
}
}
Run Code Online (Sandbox Code Playgroud)
替代方法:确保在任何帧渲染期间不会消耗多于一个更新,如果更新处于挂起状态,则阻止后台线程
这是一种有点不同的方法.创建一个BlockingQueue
容量1
来容纳Runnable
更新UI 的s.从后台线程中,将Runnable
s 提交到阻塞队列:由于阻塞队列最多只能容纳一个元素,因此如果一个元素已经挂起,这将阻止.
要实际执行队列中的更新(并删除它们,以便可以添加更多),请使用AnimationTimer
.这看起来像:
private final BlockingQueue<Runnable> updateQueue = new ArrayBlockingQueue<>(1);
Run Code Online (Sandbox Code Playgroud)
后台线程代码:
// 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
Run Code Online (Sandbox Code Playgroud)
创建计时器以使用更新:
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();
Run Code Online (Sandbox Code Playgroud)
这基本上确保了在任何时候都不会安排多于一个更新,后台线程会阻塞,直到消耗任何挂起的更新.动画计时器检查(不阻止)每个帧渲染的挂起更新,确保每次更新都执行.这种方法的好处在于,您可以增加阻塞队列的大小,有效地保留挂起的更新缓冲区,同时仍确保在任何单帧渲染期间不会消耗多于一个更新.如果偶尔计算花费的时间比其他计算时间长,这可能会有用; 它为这些计算提供了计算的机会,而其他计算则等待执行.
归档时间: |
|
查看次数: |
5364 次 |
最近记录: |