【问题标题】:JavaFX multiple tasksJavaFX 多任务
【发布时间】:2018-11-18 01:58:19
【问题描述】:

有人可以帮帮我吗? 我有一个使用 JavaFX 的程序。 现在按下按钮后,我想做 n 次计算。 这些计算应该使用线程(并行)完成,它们不应该使主要的 JavaFX 应用程序挂起/冻结。我想要做的是在计算运行时显示加载状态,如果所有任务都完成计算,我想继续程序(删除加载状态并显示结果)。

在阅读了一些关于“JavaFX 中的并发”的内容后,我想到了这个:

for (int i = 0; i < n; ++i) {
    CalcTask task = new CalcTask(i);

    task.setOnSucceeded(e -> {
        // process is just a static method in which I count 
        // how many results (i) I already received 
        // (where n is the required amount). If i == n,
        // I know I am done with all the tasks
        process(task.getValue());
    });

    new Thread(task).start();
}

还有 CalcTask 类:

public class CalcTask extends Task<Integer> {
    protected int id;

    public CalcTask (int id) {
        this.id = id;
    }

    @Override
    public Integer call() {
        return CALCULATION_RESULT;
    }
}

现在我的问题是:这对我来说似乎有点“笨拙”。有没有更好的方法在 JavaFX 中实现这样的东西?谢谢:)

【问题讨论】:

    标签: java javafx concurrency parallel-processing task


    【解决方案1】:

    由于您扩展了Task类,您还可以覆盖方法succeeded()并删除主线程上对task.setOnSucceeded()的调用:

    for (int i = 0; i < n; ++i) {
      CalcTask task = new CalcTask(i);
      new Thread(task).start();
    }
    
    public class CalcTask extends Task<Integer> {
        protected int id;
    
        public CalcTask (int id) {
            this.id = id;
        }
    
        public void succeeded() {
           process(this.getValue());
        }
    
        @Override
        public Integer call() {
            return CALCULATION_RESULT;
        }
    }
    

    甚至使用普通的Runnable 代替Task

    public class CalcTask implements Runnable {
        protected int id;
    
        public CalcTask (int id) {
            this.id = id;
        }
    
        @Override
        public void run() {
           CALCULATION_RESULT = calculate();
           process(CALCULATION_RESULT);
        }
    }
    

    【讨论】:

    • 只是想指出你的两个例子是不等价的。 Task.succeeded 方法将在 FX 线程上调用 process,而纯 Runnable 将在调用 run 的任何线程上调用 process
    • 谢谢!我会在今天晚些时候试一试,然后回来对此发表评论。
    • 好的,谢谢你的回答。我最终像这样实现它(任务变体)。如果没有“更清洁”的方式来实现这一点,我仍然有点好奇。我正在考虑一个“容器”,它包含所有任务 - 如果所有任务都已完成,“容器”将触发一个事件,您可以获取所有任务结果。但无论如何 - 谢谢!
    【解决方案2】:

    在我看来,更好的方法是 RxJavaFx
    此示例:https://github.com/pkrysztofiak/rxjavafx-demo
    RxJavaFx 教程https://github.com/ReactiveX/RxJavaFX

    package com.github.pkrysztofiak.rxjavafx.rxjavafxdemo.concurrency;
    
    import java.util.Random;
    
    import io.reactivex.Observable;
    import io.reactivex.rxjavafx.observables.JavaFxObservable;
    import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
    import io.reactivex.schedulers.Schedulers;
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.layout.HBox;
    import javafx.stage.Stage;
    
    public class ParallelTasksApp extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage stage) throws Exception {
            Button button = new Button("Start");
            Label label = new Label();
            HBox hBox = new HBox(button, label);
            stage.setScene(new Scene(hBox));
            stage.show();
    
            JavaFxObservable.actionEventsOf(button)
            .flatMap(actionEvent -> Observable.range(1, 4))
            .flatMap(i -> Observable.just(i)
                    .subscribeOn(Schedulers.newThread())
                    .map(this::runLongProcess))
            .observeOn(JavaFxScheduler.platform())
            .scan(0, (aggregator, next) -> ++aggregator)
            .map(String::valueOf)
            .subscribe(label::setText);
        }
    
        private int runLongProcess(int i) {
            try {
                Thread.sleep(new Random().nextInt(10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " i=" + i);
            return i;
        }
    }
    

    【讨论】:

    • 嗨 - 感谢您的回答,但我不喜欢过多的方法链接。也许对某些人来说这是一个优雅的解决方案,但遗憾的是对我来说不是。我仍然非常感谢你的贡献:)
    猜你喜欢
    • 2014-05-23
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-09-20
    相关资源
    最近更新 更多