1

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

请看一下这个最小的例子:

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 实例。

是否有一个原因?如何实现只显示一个对话框并显示进度?

4

2 回答 2

2

考虑Swing 的线程策略

一般来说,Swing 不是线程安全的。除非另有说明,否则所有 Swing 组件和相关类都必须在事件调度线程上访问。

这意味着您必须研究ProgressMonitor的文档以了解“除非另有说明”是否适用,但由于没有其他线程策略,因此这里没有什么可引用的。

在 Event Dispatch Thread 中执行操作的一种方法是将其封装在 a 中Runnable并使用invokeLater(Runnable),但是当这样做是为了从未知数量的工作线程发送不同的进度状态时,它们可能会以错误的顺序到达,而且效率也会很低. 既然你已经有了一个AtomicInteger,更好的选择是使用一个SwingTimer

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();
    }
}
于 2020-12-18T10:49:23.943 回答
0

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

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

于 2020-12-18T10:46:29.613 回答