我有一个与某些数据关联的TableView,一旦我点击了一个运行按钮,我就对该数据执行了一些处理。每行数据都是在一个单独的线程中处理的,当这些线程正在运行时,我想要一个ProgressInducator来替换它的vbox中的表。
附带的代码:
如果我停在哪里说“停止在这里工作” - 表格被替换为pi。 如果我继续等待线程加入 - 没有替换。 我错过了什么?
runButton.setOnAction(
new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent e) {
List<Thread> threadList = new ArrayList<Thread>();
int threadCounter = 0;
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
for (ProductInTable product : data) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
threadList.add(thread);
thread.start();
}
int x = threadList.size();
/** WORKS IF STOP HERE **/
// wait for all threads to end
for (Thread t : threadList) {
try {
t.join();
threadCounter++;
pi.setProgress(threadCounter / x);
} catch (InterruptedException interE) {
interE.printStackTrace();
}
}
/** DOESNT WORKS IF STOP HERE **/
答案 0 :(得分:0)
Thread.join()
阻止执行,直到线程完成。由于您在FX应用程序线程上调用此方法,因此您将阻止该线程直到所有工作线程完成。这意味着在这些线程完成之前,UI无法更新。
更好的方法可能是用任务表示每个计算,并使用setOnSucceeded
在FX应用程序线程上更新完整任务的计数器。类似的东西:
runButton.setOnAction(
new EventHandler<ActionEvent>() {
@Override
public void handle(final ActionEvent e) {
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
final int numTasks = data.size();
// only access from FX Application thread:
final IntegerProperty completedTaskCount = new SimpleIntegerProperty(0);
pi.progressProperty().bind(completedTaskCount.divide(1.0*numTasks));
completedTaskCount.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) {
if (newValue.intValue() >= numTasks) {
// hide progress indicator and show table..
}
}
});
for (final ProductInTable product : data) {
Task<Void> task = new Task<Void>() {
@Override
public Void call() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null ;
}
});
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
completedTaskCount.set(completedTaskCount.get()+1);
}
});
new Thread(task).start();
}
}
});
如果您可能在此处拥有大量项目,则应使用某种ExecutorService
来避免创建太多线程:
ExecutorService exec = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()); // for example...
然后替换
new Thread(task).start();
与
exec.submit(task);