java - Java JavaFX 应用程序中的多线程问题

标签 java multithreading javafx

我正在编写一个程序,该程序要实时完成大量工作,它处理视频中的图像并在 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/

相关文章:

java - 比较整数集合

c# - C#多线程的速度测试

ruby-on-rails - 我可以在Rails应用程序的Heroku上使用Puma线程吗?

java - 默认关闭时在 TabPane 中使用的选项卡

java - 无法在 JavaFX 中为我的 TableColumn 设置不同的值

java - 如何在不在 JPA 中加载相关实体的情况下使用外键保存实体?

java - 重新启动应用程序后 SQLite DB 被删除

java - 获取两个字符串日期之间的记录

regex - 带有子例程的线程不返回任何内容

JavaFX检测场景外的鼠标移动