ExecutorService调用所有进度条 [英] ExecutorService InvokeAll Progress Bar

查看:140
本文介绍了ExecutorService调用所有进度条的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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 Futures 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆