ExecutorService调用所有进度条 [英] ExecutorService InvokeAll Progress Bar
问题描述
我有一个ExectorService和以下代码,期货和并发一切正常。但是,当我尝试从SomeClass()更新进度条时,似乎仅在invokeAll()完成后才更新UI ...基本上,进度条仅在一切都完成后才更新,认为它无用。
I have an ExectorService and the following code, everything is working fine with the futures and the concurrency. However, when I try to update my progress bar from SomeClass(), it seems to only update the UI after the invokeAll() is complete...basically the progress bar only updates once everything is complete which deems it useless.
我该如何解决?我看过CompletionServices和SwingWorkers,但是我不知道如何将它们应用于我的代码。
How can I resolve this? I've looked at CompletionServices as well as SwingWorkers but I don't know how to apply them to my code. Any assistance will be appreciated.
class SomeClass() {
private static class Result {
private final String someVar;
public Result(String code) {
this.someVar = code;
}
}
public static Result compute(Object obj) {
// ... compute stuff
someVar = "computedResult";
return Result(someVar);
}
public someFunction() {
List<Callable<Result>> tasks = new ArrayList<Callable<Result>>();
for (Object f : listOfObjects) {
Callable<Result> c = new Callable<Result>() {
@Override
public Result call() throws Exception {
someClassUI.jProgressBar.setValue(50);
return compute(file);
}
};
tasks.add(c);
}
List<Callable<Result>> tasks = new ArrayList<Callable<Result>>();
List<Future<Result>> results = executorService.invokeAll(tasks);
for (Future<Result> fr : results) {
String value = fr.get().resultValue;
}
}
}
class SomeClassUI {
public static jProgressBar;
public someClassUI() {
jProgressBar = new JProgressBar(0,100);
}
private void button1ActionPerformed(ActionEvent e) {
SomeClass theClass = new SomeClass();
theClass.someFunction();
}
}
编辑:编辑后添加了一些额外的代码来帮助理解
edit: edited to add some extra code to help understanding
推荐答案
我一直在测试与您相似的代码,直到意识到
I've been testing with code similar to yours, until I realized the following:
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException
全部完成时 是导致进度条行为的原因。换句话说,如果仅在所有任务完成时才获得 Future
的列表,那么很显然,对其进行迭代并更新条形将是如此之快,以至于您只能看到
That "when all complete" is what is causing the behaviour of the progress bar. In other words, if you get the list of Future
only when all tasks complete, then, obviously, iterating over them and updating the bar would be so fast that you see only the last update, when the bar is full.
像我一样,您可以做的就是调用 submit
每个任务,并将 Future
s分别添加到列表中。
What you could do, like I did, is calling submit
for each of your tasks, and add the Future
s individually to a list.
下面的示例代码已经过测试,可以在这里工作。您应该能够使其适应自己的目的。
The example code below has been tested, and works here. You should be able to adapt it to your own purposes.
侦听器界面:
public interface UpdateListener {
void update(double percent);
}
任务执行器:
public class SomeClass {
// instance variables
private UpdateListener listener;
private ExecutorService executor;
/** Parameter constructor of objects of class SomeClass. */
public SomeClass(UpdateListener l) {
listener = l;
executor = Executors.newFixedThreadPool(4);
}
/** */
public void doIt() throws InterruptedException, ExecutionException {
int numOfTasks = 5, completedTasks = 0;
List<Future<Integer>> results = new ArrayList<>();
// Submit each of your tasks. Here I create them manually.
for (int i = 0; i < numOfTasks; ++i) {
final int I = i;
Callable<Integer> c = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
try {
Thread.sleep((long) I * 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return new Integer(I);
}
};
results.add(executor.submit(c));
}
// Retrieve individual results and update progress bar.
for (Future<Integer> fr : results) {
Integer i = fr.get();
++completedTasks;
listener.update((double) completedTasks / numOfTasks);
}
}
}
UI类:
public class SomeClassUI implements Runnable, UpdateListener {
// instance variables
private JProgressBar bar;
private JFrame frame;
private SomeClass t;
/** Empty constructor of objects of class SomeClassUI. */
public SomeClassUI() {
t = new SomeClass(this);
}
/** Builds the interface. */
public void run() {
bar = new JProgressBar(0, 100);
bar.setStringPainted(true);
JPanel panel = new JPanel(new FlowLayout());
panel.setPreferredSize(new Dimension(200, 100));
panel.add(bar);
frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
/** Method from the interface. Updates the progress bar. */
@Overrides
public void update(double percent) {
final double PERCENT = percent;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int v = (int) (100 * PERCENT);
bar.setValue(v);
}
});
}
/** Tests the program. */
public void go() {
SwingUtilities.invokeLater(this);
try {
t.doIt();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main() {
new SomeClassUI().go();
}
}
这篇关于ExecutorService调用所有进度条的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!