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

wlwcrazw  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(355)

我有一种奇怪的行为我无法解释。
请看一下这个最小的例子:

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示例出现。
有什么原因吗?我怎样才能做到只有一个对话框出现并显示进度?

qvtsj1bj

qvtsj1bj1#

考虑swing的线程策略:
一般来说,swing不是线程安全的。除非另有说明,否则必须在事件调度线程上访问所有swing组件和相关类。
这意味着你必须学习 ProgressMonitor 的文档来确定“除非另有说明”是否适用,但是由于没有其他线程策略,这里没有什么可引用的。
在事件调度线程中执行操作的一种方法是将其封装在 Runnable 使用 invokeLater(Runnable) ,但是当这样做是为了从未知数量的工作线程发送不同的进度状态时,它们可能会以错误的顺序到达,而且效率也会非常低。既然你已经有了 AtomicInteger ,更好的选择是使用秋千 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();
    }
}
3qpi33ja

3qpi33ja2#

是否真的需要使用并行处理?如果不更换 belege.stream().parallel().forEach(b ->belege.stream().forEach(b -> ,它应该能解决你的问题。
并行执行将涉及更多线程,因此将从不同上下文对进度监视器进行多个调用。每个线程将显示一个进度ui,最终您将拥有多个进度ui。因此,如果您没有真正的理由使用并行执行,请使用顺序执行。

相关问题