java - 使用 countDownLatch 更新两个或多个 ProgressBar

标签 java multithreading user-interface javafx countdownlatch

我正在学习带进度条的多线程。我在以下简单代码中没有问题地获得了更新:

public class Controller implements Initializable {
@FXML
private Button id_boton1;
@FXML
private Button id_boton2;

@FXML
private ProgressBar id_progressbar1;
@FXML
private ProgressIndicator id_progressindicator1;

@Override
public void initialize(URL location, ResourceBundle resources) {
    id_progressbar1.setProgress(0.0);
    id_boton1.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            Thread hiloProgressBar= new Thread(new bg_Thread1());
            //hilo.setDaemon(true);
            hiloProgressBar.start();
        }
    });

    id_boton2.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            Thread hiloProgressIndicate = new Thread(new bg_Thread2());
            hiloProgressIndicate.start();
        }
    });



}

class bg_Thread1 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            id_progressbar1.setProgress((float)i/99);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);

        }
    }
}

class bg_Thread2 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            id_progressindicator1.setProgress((float)i/99);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);

        }
    }
}}

没什么特别的。 2 个按钮,用于创建带有作业和进度条的线程。

我的问题是关于这个程序的 CountDownLatch 的实现。我想等待两个线程完成。现在 UI 不会随着进度条的变化而刷新

public class Controller implements Initializable {
@FXML
private Button id_boton1;


@FXML
private ProgressBar id_progressbar1;
@FXML
private ProgressIndicator id_progressindicator1;

@Override
public void initialize(URL location, ResourceBundle resources) {



    CountDownLatch countDownLatch = new CountDownLatch(2);

    id_progressbar1.setProgress(0.0);
    id_boton1.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {

            System.out.println("iniciando Threads");

            Thread hiloProgressBar= new Thread(new bg_Thread1(countDownLatch));
            hiloProgressBar.start();

            Thread hiloProgressIndicate = new Thread(new bg_Thread2(countDownLatch));
            hiloProgressIndicate.start();

            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("*fin*");
        }
    });


}

class bg_Thread1 extends Thread{

    private CountDownLatch latch;

    public bg_Thread1(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            id_progressbar1.setProgress((float)i/99);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);

        }
        latch.countDown();
    }
}

class bg_Thread2 extends Thread{

    private CountDownLatch latch;

    public bg_Thread2(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        for (int i = 0; i < 40; i++) {
            id_progressindicator1.setProgress((float)i/39);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);

        }
        latch.countDown();
    }
}}

现在,一个按钮启动两个线程,当工作完成时,progressBar 更新一次

最佳答案

CountDownLatch 非常适用于您希望将 SQL 查询分成更小的查询并等待所有查询返回的情况。然后只有在所有结果都完成后才合并您的结果。我不确定你是否真的需要它......你可以在状态“成功”时添加一个事件处理程序。对于这个例子,我在相应的线程完成后将标签更改为“已完成”。如果您需要等待它们全部完成才能做其他事情,那么您需要将闩锁封装在另一个线程中。 latch.await() 如果在 UI 线程上运行将卡住 UI。

更新: 我已经实现了 CountDownLatch,因为您需要等待两个线程完成才能执行其他操作。


enter image description here enter image description here enter image description here enter image description here


import java.util.concurrent.CountDownLatch;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
import javafx.stage.*;

public class ProgressTest extends Application
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage)
    {

        Button getButton = new Button("Copy");

        ProgressBar progressBar = new ProgressBar(0);
        ProgressIndicator progressIndicator = new ProgressIndicator(0);
        progressBar.setProgress(0);
        progressIndicator.setProgress(0);
        Label statusLabel1 = new Label();
        Label statusLabel2 = new Label();
        VBox vBox = new VBox();
        vBox.getChildren().addAll(statusLabel1, statusLabel2, progressBar, progressIndicator, getButton);
        vBox.setAlignment(Pos.CENTER);

        getButton.setOnAction((ActionEvent e) ->
        {

            CountDownLatch countDownLatch = new CountDownLatch(2);

            // Create a Task.
            CopyTask copyTask1 = new CopyTask(30, countDownLatch);
            CopyTask copyTask2 = new CopyTask(50, countDownLatch);
            progressBar.progressProperty().unbind();
            // Bind progress property
            progressBar.progressProperty().bind(copyTask2.progressProperty());

            progressIndicator.progressProperty().unbind();
            // Bind progress property.
            progressIndicator.progressProperty().bind(copyTask1.progressProperty());

            // Unbind text property for Label.
            statusLabel1.textProperty().unbind();
            statusLabel2.textProperty().unbind();

            // Bind the text property of Label
            // with message property of Task
            statusLabel1.textProperty().bind(copyTask1.messageProperty());
            statusLabel2.textProperty().bind(copyTask2.messageProperty());

            // When completed tasks
            copyTask1.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, (WorkerStateEvent t) ->
            {
                statusLabel1.textProperty().unbind();
                statusLabel1.setText("Finished1");
            });
            copyTask2.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, (WorkerStateEvent t) ->
            {
                statusLabel2.textProperty().unbind();
                statusLabel2.setText("Finished2");

            });

            Task<Void> task = new Task<Void>()
            {
                @Override
                public Void call() throws InterruptedException
                {

                    // Start the Task.
                    new Thread(copyTask1).start();
                    new Thread(copyTask2).start();
                    countDownLatch.await();
                    return null;

                }
            };

            task.setOnSucceeded(event ->
            {
                System.out.println("This occurs after both threads complete...");

            });

            task.setOnFailed(event ->
            {
                System.out.println("FAIL...");
            });

            Thread thread = new Thread(task);
            thread.start();

        });

        final Scene scene = new Scene(vBox);

        primaryStage.setScene(scene);

        primaryStage.show();
    }

    public class CopyTask extends Task<Void>
    {

        int x;
        CountDownLatch latch;

        public CopyTask(int x, CountDownLatch latch)
        {
            super();
            this.x = x;
            this.latch = latch;

        }

        @Override
        protected Void call() throws Exception
        {
            //don't do the infitnite progress meter ...
            this.updateProgress(0, x);

            try
            {

                int len;
                for (len = 0; len <= x; len++)
                {
                    this.updateProgress(len, x);
                    Thread.sleep(100);
                    if (this.isCancelled())
                    {
                        throw new InterruptedException();
                    }
                }

                if (this.isCancelled())
                {
                    throw new InterruptedException();
                }
            } catch (InterruptedException ex)
            {
                System.out.println("Cancelled");
            }
            latch.countDown();
            return null;

        }

    }

}

关于java - 使用 countDownLatch 更新两个或多个 ProgressBar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57626268/

相关文章:

java - Solr - 匹配以特定单词开头的句子

multithreading - Clojure 实现多线程的最佳方式?

android - 用于更新小部件的 AsyncTask - 如何访问 onPostExecute() 中的 TextView ?

java - 是什么阻止了我的进度条更新?

Java 不加载嵌入图像

java - Angular 6 Spring Boot POST 问题

java - 使用正则表达式从包含换行符的文本中解析字符串

java - 设置 int 值会导致性能问题

JavaFX TextField cancelEdit 未按预期工作

java - 将按钮存储到变量