JavaFX несколько задач - PullRequest
       29

JavaFX несколько задач

0 голосов
/ 18 ноября 2018

Может кто-нибудь помочь мне? У меня есть программа, которая использует 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? Спасибо:)

Ответы [ 2 ]

0 голосов
/ 18 ноября 2018

На мой взгляд, лучший способ это 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;
    }
}
0 голосов
/ 18 ноября 2018

Поскольку вы расширяете класс 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);
    }
}
...