【问题标题】:Do I need to use thread and a task in JavaFX to run something in background when a thread will do the job?当线程完成这项工作时,我是否需要使用 JavaFX 中的线程和任务在后台运行某些东西?
【发布时间】:2017-06-13 03:34:30
【问题描述】:

我正在使用线程定期运行三秒背景动画。
我从一个用 Swing 编写的 Thread Demo 示例中改编了有问题的代码,并使用了 它取代了使用线程和任务的不太正常的早期版本。

我的程序在播放视频或运行动画时停止/暂停线程 并在结束视频或动画时启动一个新线程。这似乎没有 任何缺点,这就是为什么我很困惑为什么我之前的 JavaFX 搜索没有出现 与我正在使用的解决方案类似。这似乎是一种相当直接的跑步方法 简短的背景动画。

我在哪里做错了?我错过了什么?我将如何重写这段代码 同时使用 Thread 和 Task 还是我需要?

我应该补充一下 - while 和 run 语句与原始语句几乎没有变化 Swing 代码的唯一重要补充是添加 thread.setDaemon( true ) 开始线程()。

播客听众。

// background thread
class BackGround extends Thread {
    @Override
    public void run() {
        while ( suspend.getValue() == false ) {
            try {
                 int r = shared.randInt( 5, 10 );
                 Thread.sleep( r * 1000 );            
            } catch ( InterruptedException e ) {
                // do nothing
        }
        if ( suspend.getValue() == false )  {
            Platform.runLater( () -> { 
                 int g = shared.cssGradients.length - 1;
                 g = shared.randInt( 0, g );       
                 gradientColor.set( shared.cssGradients[g] );
                 Boolean bif = shared.updatePanes( shared.cssGradients[g], 
                                      leftPane, rightPane );   

            });
        }
      }
    }   
}   // class background

// start thread
public synchronized void startThread() {
    thread = new BackGround();  // Thread thread ...defined elsewhere
    thread.setDaemon( true );
    thread.start();
}

// stop thread
public synchronized void stopThread() {
    suspend.set( true );
}

【问题讨论】:

    标签: multithreading javafx


    【解决方案1】:

    Task 类对 JavaFX 有用的原因是它提供了许多回调,如 succeeded()failed()cancelled() 以及将在 JavaFX 中运行的 updateProgress()updateMessage() 等方法应用程序线程,因此让您无需 Platform.runLater( () -> { ... }); 即可更新 UI 这使得 Task 类成为执行后台任务(如下载数据或长时间运行的计算)的完美选择。

    但是,由于您的线程只是连续运行而从未真正完成其工作,因此您似乎不需要Task 为您提供的任何其他功能,而不是简单的Thread

    不过,如果您真的想将代码转换为使用 Task,它看起来就像这样:

    class BackGround extends Task<Void> {
    
        @Override
        protected Void call() throws Exception {
            while (suspend.getValue() == false) {
                try {
                    int r = shared.randInt(5, 10);
                    Thread.sleep(r * 1000);
                } catch (InterruptedException e) {
                    // do nothing
                }
                if (suspend.getValue() == false) {
                    Platform.runLater(() -> {
                        int g = shared.cssGradients.length - 1;
                        g = shared.randInt(0, g);
                        gradientColor.set(shared.cssGradients[g]);
                        Boolean bif = shared.updatePanes(shared.cssGradients[g],
                                leftPane, rightPane);
    
                    });
                }
            }
            return null;
        }
    }
    
    // start thread
    public synchronized void startThread() {
        Task<Void> bg = new BackGround();
        Thread taskThread = new Thread(bg);
        taskThread.setDaemon(true);
        taskThread.start();
    }
    
    // stop thread
    public synchronized void stopThread() {
        suspend.set( true );
    }
    

    如您所见,这对您来说并没有什么不同,因为您不需要 Thread 无法给您的任何东西。但是,如果您想与 UI 线程进行更密切的通信,例如显示进度条或显示状态更新,然后Task 将为您提供执行此操作的工具。

    我想还值得一提的是,使用Timeline 来触发动画会非常优雅。它看起来有点像这样:

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            int g = shared.cssGradients.length - 1;
            g = shared.randInt(0, g);
            gradientColor.set(shared.cssGradients[g]);
            Boolean bif = shared.updatePanes(shared.cssGradients[g], leftPane, rightPane);
        }
    }
    ));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();
    

    handle() 方法中的代码每秒在 JavaFX 应用程序线程中运行。不幸的是,这只能让您设置执行之间的固定时间,而您似乎每次都希望等待随机的时间。

    TL;DR:使用Thread 是可以的,因为在您的用例中不需要Task 的额外功能。

    【讨论】:

    • 再次感谢我的最后一条评论。
    • 我尝试使用您的建议并将我的线程更改为任务,但它无法编译:dots.java:633:警告:[rawtypes] 找到原始类型:任务类背景扩展任务 { 缺少类型泛型类 Task 的参数,其中 V 是类型变量:V 扩展类 Task java:662 中声明的对象:警告:[rawtypes] 找到原始类型:Task Task task = new BackGround();缺少泛型类 Task 的类型参数,其中 V 是类型变量:V 扩展在类 Task .java:656 中声明的对象:错误:缺少返回语句} 1 错误 2 警告
    • 对不起,原来我搞砸了一些事情,请参阅我编辑的答案。它没有编译的原因是因为 return null; call() 方法中缺少语句。您的编译器发出的警告来自我省略了类的类型参数(扩展了 Task)。此外,我修复了在 startThread() 方法中正确启动任务的问题。很抱歉,它现在应该使用这些更改进行编译。
    • 是的,已接受。您的更改已编译并且程序似乎像以前一样运行,当时它完全是线程驱动的。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2016-12-04
    • 2016-02-26
    • 1970-01-01
    相关资源
    最近更新 更多