Java 带有Progressmonitor的并行流打开多个对话框

Java 带有Progressmonitor的并行流打开多个对话框,java,swing,java-stream,progressmonitor,Java,Swing,Java Stream,Progressmonitor,我有一种奇怪的行为,我无法解释 请看一下这个最小的示例: public class ParallelStreamProgressMonitor { public static void main(String[] args) { List<Integer> belege = IntStream.range(1, 100).boxed().collect(Collectors.toList()); final ProgressMonito

我有一种奇怪的行为,我无法解释

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

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
            }
        });
    }
}
公共类ParallelStreamProgressMonitor
{
公共静态void main(字符串[]args)
{
List belege=IntStream.range(1100.boxed().collect(Collectors.toList());
final ProgressMonitor pm=new ProgressMonitor(空,“初始消息”,“初始注释”,0,belege.size());
pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0);
pm.setMaximum(belege.size());
pm.setNote(“现在我在工作”);
AtomicInteger计数器=新的AtomicInteger();
belege.stream().parallel().forEach(b->
{
系统输出打印ln(b);
pm.setProgress(counter.getAndIncrement());
尝试
{
//一些耗时的事情。。。
睡眠(1000);
}
捕捉(中断异常e)
{
//忽略
}
});
}
}
在执行此操作时,您通常希望出现ProgressMonitor并显示执行进度

但实际上情况是这样的:

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


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

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

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

考虑:

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

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

在事件分派线程中执行操作的一种方法是将其封装在可运行的
中并使用,但是当执行此操作以从未知数量的工作线程发送不同的进度状态时,它们可能会以错误的顺序到达,而且效率也会非常低。因为您已经有了
AtomicInteger
更好的选择是使用:

公共类ParallelStreamProgressMonitor
{
公共静态void main(字符串[]args)
{
名单
=IntStream.range(1100).boxed().collect(Collectors.toList());
最终进度监视器pm=新进度监视器(
null,“Initialmessage”,“initialnote”,0,belege.size());
pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0);
pm.setMaximum(belege.size());
pm.setNote(“现在我在工作”);
AtomicInteger计数器=新的AtomicInteger();
定时器=新定时器(250,ev->pm.setProgress(counter.get());
timer.start();
belege.stream().parallel().forEach(b->
{
系统输出打印ln(b);
counter.getAndIncrement();
//模拟一些耗时的事情。。。
锁支持.parknos(时间单位.毫秒.toNanos(1000));
});
timer.stop();
}
}

ProgressMonitor的文档中是否有任何内容表明从不同线程使用它是安全的?我找不到任何关于这一点的内容。但我想我找到了解决方案…请参阅editDon't post solutions in the question。这就是答案部分的目的。此外,从不同的线程访问Swing组件同步了
的线程仍然不符合Swing的线程策略。它可能只工作一次,但不能保证继续工作。除此之外,它效率低下。谢谢,你是对的。我删除了它。是的,在我的情况下,我有一个非常大的集合要处理(可以并行处理)。