发布/处理使 SwingWorker 变慢

Posted

技术标签:

【中文标题】发布/处理使 SwingWorker 变慢【英文标题】:publish/process makes the SwingWorker slow 【发布时间】:2012-12-07 16:26:03 【问题描述】:

我尝试使用 SwingWorker 来更新进度条。对我来说没有什么新鲜事。我有点懒,所以我没有覆盖 process 方法。这里是一个简化的例子:

protected Void doInBackground() throws Exception 
    for (int i = 0; i < 10000; i++) 
        progressBar.setValue(i+1);            
    
    return null;

在我的电脑上,将进度条更新到 100% 大约需要 6 秒。现在是星期五,所以我想让我们以一种不同的方式来做这件事,就像经常描述的那样。让我们使用 publish 和 process 方法来更新进度条:

@Override
protected Void doInBackground() throws Exception 
    for (int i = 0; i < maximum; i++)             
        publish(i+1);
    
    return null;


@Override
protected void process(List<Integer> chunks)         
    progressBar.setValue(chunks.get(chunks.size()-1));

但是现在使用发布方法需要 21(而不是 6)秒才能将进度条更新到 100%。

为什么?

这里是整个代码(带有“开始”按钮和进度条的框架):

public class Gui extends JFrame 

    public static void main(String[] args) 
        new Gui();
    

    public Gui() 
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JProgressBar progressBar = new JProgressBar();
        progressBar.setStringPainted(true);

        JButton btnStart = new JButton("Start");
        btnStart.addActionListener(new ActionListener() 

            @Override
            public void actionPerformed(ActionEvent e) 
                new MySwingWorker(progressBar).execute();
            
        );

        getContentPane().setLayout(new BorderLayout(3, 3));
        getContentPane().add(btnStart, BorderLayout.CENTER);
        getContentPane().add(progressBar, BorderLayout.SOUTH);
        pack();
        setVisible(true);
        setLocationRelativeTo(null);
    

    private class MySwingWorker extends SwingWorker<Void, Integer> 

        private final int MAXIMUM = 100000000;
        private final JProgressBar progressBar;

        public MySwingWorker(JProgressBar progressBar) 
            this.progressBar = progressBar;
            this.progressBar.setMaximum(MAXIMUM);
            this.progressBar.setValue(0);
        

        @Override
        protected Void doInBackground() throws Exception 
            for (int i = 0; i < MAXIMUM; i++) 
                //----------------------------------
                // TOGGLE BETWEEN THESE LINES:
                //progressBar.setValue(i+1);
                publish(i + 1);
                //-----------------------------------
            
            return null;
        

        @Override
        protected void process(List<Integer> chunks) 
            progressBar.setValue(chunks.get(chunks.size() - 1));
        
    

感谢您的建议...

【问题讨论】:

没仔细看 - 但您的第一个版本错误:您不得访问 doInBackground 中的 swing 组件 是的,我知道,但它可以正常工作,而且速度提高了 70%! 6 秒而不是 21 秒。所以我的问题是:真正会发生什么? 违反 EDT 可能发生的所有邪恶事情 ;-) 难以检测,虚假(但肯定会在你最不想要的时候抛出),不可预测。所以干脆不要(而且大多数生产代码都应该防范它)。这里的问题似乎是您在不需要的情况下淹没了系统:在现实世界的场景中,您不会尝试以高于屏幕分辨率的频率更新进度条,对吧:-) 我将在我的生产系统上检查这一点。分析 500.000.000 条消息。时间差是多少。用户是否需要因为进度条而多等几分钟?我会检查一下.. 我的意思是你不想要那些数以百万计的通知:填满屏幕的进度条最多有几千个像素,所以如果通知也不会改变任何可见的东西细粒度。工人不会替换大脑 :-) 在 doInBackground 中将其分解为合理的块并仅每 100.000 个左右通知一次 【参考方案1】:

您不应该发布每一个更改,而应该每 10 次发布一次:

for (int i = 0; i < maximum; i++) 
    doTheWork();
    if(i % 10 == 0) 
        publish(i+1);
    

publish(maximum);

【讨论】:

以上是关于发布/处理使 SwingWorker 变慢的主要内容,如果未能解决你的问题,请参考以下文章

等待多个 SwingWorker

java - JLabel setForeground 在 SwingWorker 中不起作用

drawRect 使 UIScrollView 中的滚动变慢

在 swingworker 工作时禁用一切?

动画停止时如何使动画速度变慢

如果使用 SwingWorker 加载数据,何时将 TabelModel 绑定到 JTable?