我正在学习带进度条的多线程。我在以下简单代码中没有问题地获得了更新:
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
,因为您需要等待两个线程完成才能执行其他操作。
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/