Java 发布/处理会使SwingWorker变慢

Java 发布/处理会使SwingWorker变慢,java,swing,process,publish,swingworker,Java,Swing,Process,Publish,Swingworker,我已经尝试使用SwingWorker更新进度条。对我来说没什么新鲜事。我有点懒,所以没有重写process方法。下面是一个简化的示例: protected Void doInBackground() throws Exception { for (int i = 0; i < 10000; i++) { progressBar.setValue(i+1); } return null; } protectedvoid doI

我已经尝试使用SwingWorker更新进度条。对我来说没什么新鲜事。我有点懒,所以没有重写process方法。下面是一个简化的示例:

protected Void doInBackground() throws Exception {
    for (int i = 0; i < 10000; i++) {
        progressBar.setValue(i+1);            
    }
    return null;
}
protectedvoid doInBackground()引发异常{
对于(int i=0;i<10000;i++){
progressBar.setValue(i+1);
}
返回null;
}
在me PC上,将进度条更新为100%大约需要6秒钟。今天是星期五,所以我想让我们用一种不同的方式来做,就像经常描述的那样。让我们使用发布和处理方法更新进度栏:

@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));
}
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));
        }
    }
}
@覆盖
受保护的Void doInBackground()引发异常{
对于(int i=0;i<最大值;i++){
出版(i+1);
}
返回null;
}
@凌驾
受保护的无效进程(列表块){
setValue(chunks.get(chunks.size()-1));
}
但是现在使用publish方法需要21秒(而不是6秒)才能将进度条更新为100%

为什么?

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

公共类Gui扩展JFrame{
公共静态void main(字符串[]args){
新Gui();
}
公共图形用户界面(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
最终JProgressBar progressBar=新JProgressBar();
progressBar.SetStringPaint(真);
JButton btnStart=新JButton(“开始”);
btnStart.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
新建MySwingWorker(progressBar).execute();
}
});
getContentPane().setLayout(新的BorderLayout(3,3));
getContentPane().add(btnStart,BorderLayout.CENTER);
getContentPane().add(progressBar,BorderLayout.SOUTH);
包装();
setVisible(真);
setLocationRelativeTo(空);
}
私有类MyWingWorker扩展SwingWorker{
私有最终整数最大值=100000000;
私人最终JProgressBar progressBar;
公共MySwingWorker(JProgressBar progressBar){
this.progressBar=progressBar;
此.progressBar.setMaximum(最大值);
此.progressBar.setValue(0);
}
@凌驾
受保护的Void doInBackground()引发异常{
对于(int i=0;i<最大值;i++){
//----------------------------------
//在以下行之间切换:
//progressBar.setValue(i+1);
出版(i+1);
//-----------------------------------
}
返回null;
}
@凌驾
受保护的无效进程(列表块){
setValue(chunks.get(chunks.size()-1));
}
}
}

感谢您的建议…

您不应该发布每一项更改,但可能每10次发布一次:

for (int i = 0; i < maximum; i++) {
    doTheWork();
    if(i % 10 == 0) {
        publish(i+1);
    }
}
publish(maximum);
for(int i=0;i
没有仔细查看-但您的第一个版本是错误的:您不能访问DoinBackground中的swing组件是的,我知道,但它工作正常,没有任何问题,而且速度快了70%!6秒而不是21秒。所以我的问题是:到底会发生什么?违反EDT可能发生的所有坏事;-)难以察觉,虚假(但一定会在你最不想要的时候吐出来),不可预测。所以不要这样做(大多数生产代码都应该有防范措施)。这里的问题似乎是,您在无需的情况下淹没了系统:在现实世界中,您不会尝试以高于屏幕分辨率的频率更新progressbar,对吗:-)我将在我的生产系统上检查这一点。分析500.000.000条消息。时差是多少。仅仅因为进度条,用户是否需要再等待几分钟?我想说的是,你不想看到数以百万计的通知:一个填充屏幕的progressbar最多只有几千个像素,所以如果通知的粒度太细,也不会改变任何可见的内容。工作人员不更换大脑:-)在doInBackground中,将其分解为合理的块,并且仅每100.000次左右通知一次