我正在编写一个程序,该程序要实时完成大量工作,它处理视频中的图像并在 JavaFx ImageView
上显示图像,问题是我无法更新来自另一个线程的主线程组件,java不是线程安全的,所以我想了一种使用计时器的方法,一个线程总是落后,它大多挂起,所以下面是我如何实现我的代码
TimerTask frame_grabber = new TimerTask()
{
@Override
public void run()
{
processVideo();
Platform.runLater(new Runnable() {
@Override public void run() {
imageView.setImage(tmp);
}
});
}
};
timer = new Timer();
Double period = 1000 / getFPS() * 2;
this.timer.schedule(frame_grabber, 0, period.longValue());
这似乎工作得更好,但我的整个 GUI
很滞后,有人可以建议我一种更好的方法来处理视频和更新我的 UI
而不会造成任何滞后吗?
最佳答案
如果我正确理解你的问题,你基本上想通过 ImageView
显示视频,确保你不会因为发送图像的速度快于显示图像的速度而淹没 FX 应用程序线程。是这样吗?
如果是这样,您可以执行以下操作:
AtomicReference<Image> latestImage = new AtomicReference<>();
TimerTask frameGrabber = new TimerTask() {
@Override
public void run() {
if (latestImage.setAndGet(processVideo()) == null) {
Platform.runLater(() -> imageView.setImage(latestImage.setAndGet(null)));
}
}
};
// rate at which you want to sample video:
double sampleRate = ... ;
long sampleMillis = (long) 1000 / sampleRate ;
this.timer.schedule(frameGrabber, 0, sampleMillis);
在此代码中,您确保不会用太多请求淹没 FX 应用程序线程。计时器任务将 latestImage
设置为其抓取的最新图像。 Platform.runLater()
runnable 获取一个图像并将 latestImage
设置为 null
,表明它已准备好接收新图像。如果最后一个可运行项已被消耗,计时器仅将新的可运行项调度到 Platform.runLater()
。结果是 FX 应用程序线程将消耗尽可能多的图像,但如果图像的生成速度快于其消耗速度,则将跳过中间图像。
使用 AtomicReference
确保以原子方式管理在 latestImage
中检索值和设置新值,从而确保不存在竞争条件。
我假设在这里修改您的 processVideo()
方法,以便它返回它抓取的图像:
private Image processVideo() {
Image image = ... // grab image
return image ;
}
关于java - Java JavaFX 应用程序中的多线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34889826/