Я ищу подходящий способ для отображения времени обработки параллельных запущенных задач на отдельной стадии.
Я хочу выполнить различные задачи, объединенные в ArrayList - одну за другой. Для этого случая я использую ThreadPool. После каждого выполненного списка я хочу дождаться завершения всех задач. Только когда задачи достигли статуса «успешно», я хочу что-то сделать в MainThread. После этого я хочу выполнить еще один список задач и визуализировать их также на отдельной стадии. На следующем рисунке показана желаемая последовательность обработки (в зависимости от исходного кода, указанного ниже): введите здесь описание изображения
Для этого я написал классы MyLoader. MyLoader-класс содержит отдельную задачу и связывает свойства прогресса с меткой и индикатором выполнения в конструкторе:
public class MyLoader {
public Label label = null;
public ProgressBar progressBar = null;
public VBox vbox;
public Task<Integer> task = null;
public String name;
public MyLoader(String name) {
this.name = name;
this.label = new Label();
this.progressBar = new ProgressBar();
this.vbox = new VBox(2);
//UI-Layout for Progress
this.vbox.getChildren().addAll(this.label, this.progressBar);
HBox.setHgrow(this.vbox, Priority.ALWAYS);
this.vbox.setAlignment(Pos.CENTER);
this.progressBar.prefWidthProperty().bind(this.vbox.widthProperty().subtract(20));
//Counter-Size
Random r = new Random();
int max = r.nextInt((100 - 50) + 1) + 50;
//Task
this.task = new Task<Integer>() {
@Override
protected Integer call() throws Exception {
int idx = 0;
while(idx <= max) {
Thread.sleep(20); //... for long lasting processes
updateMessage(name+"-progress: "+idx);
updateProgress(idx, max);
idx++;
}
return max;
}
protected void succeeded() {
updateMessage(name+" succeeded!");
System.out.println(name+" succeeded!");
super.succeeded();
}
};
//Bind Properties
this.label.textProperty().bind(task.messageProperty());
this.progressBar.progressProperty().bind(task.progressProperty());
}
}
В MainClass я объединяю несколько экземпляров MyLoader в ArrayList и запускаю их с помощью ExecutorService. Для создания нового этапа я использую stati c метод progressStage (List). Каждый этап отображается до того, как ExecutorService выполнит соответствующие задачи. Вот код MainClass:
public class MainClass extends Application{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
//Thread-Pool
ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
//FirstLoaders
List<MyLoader> firstLoaders = new ArrayList<MyLoader>();
firstLoaders.add(new MyLoader("A"));
firstLoaders.add(new MyLoader("B"));
//Show 1. Stage
Stage firstStage = progressStage(firstLoaders);
firstStage.show();
//Execute firstLoaders
for(MyLoader l1 : firstLoaders)
es.execute(l1.task);
//1) TODO: How can I wait for the completion of the first loaders and start the second loaders?
//... doSomething1() ...
//SecondLoaders
List<MyLoader> secondLoaders = new ArrayList<MyLoader>();
secondLoaders.add(new MyLoader("C"));
secondLoaders.add(new MyLoader("D"));
secondLoaders.add(new MyLoader("E"));
//Show 2. Stage
Stage secondStage = progressStage(secondLoaders);
secondStage.setX(firstStage.getX());
secondStage.setY(firstStage.getY()+firstStage.getHeight());
secondStage.show();
for(MyLoader l2 : secondLoaders)
es.execute(l2.task);
//2) TODO How can I wait for the completion of the second loaders and start the primaryStage?
//... doSomething2() ...
Scene scene = new Scene(new StackPane(), 450, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
static Stage progressStage(List<MyLoader> loaderTasks) {
int count = loaderTasks.size();
VBox loadBox = new VBox(count);
for(int i=0; i<count; i++)
loadBox.getChildren().add(loaderTasks.get(i).vbox);
HBox.setHgrow(loadBox, Priority.ALWAYS);
loadBox.setAlignment(Pos.CENTER);
Stage dialogStage = new Stage();
dialogStage.setScene(new Scene(loadBox, 300, count * 50));
dialogStage.setAlwaysOnTop(true);
return dialogStage;
}
}
Программа пока выполняется, но последовательность вычислений выглядит полностью параллельной.
То, что я попробовал:
1) До сих пор мне удалось заставить процесс считываться и останавливаться с помощью метода get () , Но тогда сцена отображается только тогда, когда потоки в фоновом режиме закончили свою работу.
//1) TODO: „doSomeThing1()“
List<Integer> integers = new ArrayList<Integer>();
for(MyLoader ml : firstLoaders)
integers.add(ml.task.get());
System.out.println(integers.toString());
2) Также с помощью метода Task.setOnSucceded () я пока не смог получить никаких полезных результатов. Главным образом потому, что этап показан только после вычислений. Проблема в том, что я не могу запросить состояние всех задач в определенное время.
3) Применение CountDownLatch также достигло сопоставимого результата.
4) Кроме того , метод shutdown () в ExecutorService вызывает завершение. Поэтому это решение также не подходит.
//1) TODO: „doSomeThing1()“
es.shutdown();
try {
es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
//SecondLoaders
//...
}catch (InterruptedException e) {
e.printStackTrace();
}
Есть ли подходящий подход для таких намерений? До сих пор я не пришел ни к какому полезному результату.