通过使用JavaFX中的任务数组列表执行并等待多个并行和顺序任务

问题描述 投票:0回答:1

我正在寻找一种合适的方法来在单独的阶段上显示并行运行的任务的处理时间。

我想执行组合在ArrayList中的不同任务-一个接一个。对于这种情况,我正在使用ThreadPool。在每个执行的列表之后,我要等到所有任务完成。只有当任务达到“成功”状态时,我才想在MainThread中执行某些操作。之后,我想执行另一个任务列表,并在一个单独的阶段将它们可视化。下图显示了所需的处理顺序(取决于下面列出的源代码):enter image description here

为此,我编写了MyLoader类。 MyLoader类包含一个单独的Task,并在构造函数中将progress-properties与Label和Progressbar绑定:

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运行它们。为了创建新阶段,我使用静态方法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)另外,ExecutorService的shutdown()方法导致终止。因此,该解决方案也不适合。

//1) TODO: „doSomeThing1()“
es.shutdown();
try {
    es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 

    //SecondLoaders
    //...

}catch (InterruptedException e) {
    e.printStackTrace();
}

是否有适合这种意图的方法?到目前为止,我还没有得到任何有用的结果。

我正在寻找一种合适的方法来在单独的阶段显示并行运行的Task的处理时间。我想执行组合在ArrayList中的不同任务-一个接一个。为此...

javafx parallel-processing task executorservice sequential
1个回答
0
投票

完成任务后,只需更新一个计数器并检查当前完成的任务是否是当前集中的最后一个任务。

© www.soinside.com 2019 - 2024. All rights reserved.