Parallel Stream with Progressmonitor 打开多个对话框

Parallel Stream with Progressmonitor opens multiple dialogs

我有一个无法解释的奇怪行为。

请看这个最小的例子:

public class ParallelStreamProgressMonitor
{
    public static void main(String[] args)
    {
        List<Integer> belege = IntStream.range(1, 100).boxed().collect(Collectors.toList());
        final ProgressMonitor pm = new ProgressMonitor(null, "Initialmessage", "Initial Note", 0, belege.size());
        pm.setMillisToDecideToPopup(0);
        pm.setMillisToPopup(0);
        pm.setMaximum(belege.size());
        pm.setNote("Now I am working");
        AtomicInteger counter = new AtomicInteger();
        belege.stream().parallel().forEach(b ->
        {
            System.out.println(b);
            pm.setProgress(counter.getAndIncrement());
            try
            {
                //something time consuming ...
                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {
                // ignore
            }
        });
    }
}

执行此操作时,您通常会期望 ProgressMonitor 出现并显示执行进度。

但这才是真正的样子:

似乎对于每个并行流执行,都会额外显示一个 ProgressMonitor 实例。

这有什么原因吗?如何实现只显示一个对话框并显示进度?

是否真的需要使用并行处理?如果不将 belege.stream().parallel().forEach(b -> 替换为 belege.stream().forEach(b ->,它应该可以解决您的问题。

并行执行将涉及更多线程,因此将从不同的上下文对进度监视器进行多次调用。每个线程将显示一个进度 UI,最终您将拥有多个进度。因此,如果您没有真正的理由使用并行执行,请使用顺序执行。

考虑 Swing's Threading Policy:

In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread.

这意味着您必须研究 ProgressMonitor’s documentation 以确定“除非另有说明”是否适用,但由于没有其他线程策略,因此此处没有任何内容可引用。

在事件调度线程中执行操作的一种方法是将其封装在 Runnable 中并使用 invokeLater(Runnable), but when doing it for sending different progress states from an unknown number of worker threads they may arrive in the wrong order and it would also be quite inefficient. Since you already have an AtomicInteger, the better option is to use a Swing Timer:

public class ParallelStreamProgressMonitor
{
    public static void main(String[] args)
    {
        List<Integer> belege
            = IntStream.range(1, 100).boxed().collect(Collectors.toList());
        final ProgressMonitor pm = new ProgressMonitor(
                null, "Initialmessage", "Initial Note", 0, belege.size());
        pm.setMillisToDecideToPopup(0);
        pm.setMillisToPopup(0);
        pm.setMaximum(belege.size());
        pm.setNote("Now I am working");
        AtomicInteger counter = new AtomicInteger();
        Timer timer = new Timer(250, ev -> pm.setProgress(counter.get()));
        timer.start();
        belege.stream().parallel().forEach(b ->
        {
            System.out.println(b);
            counter.getAndIncrement();
            //simulate something time consuming ...
            LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
        });
        timer.stop();
    }
}