进度条更新程序使用CPU

时间:2013-03-29 20:19:49

标签: java multithreading swing event-dispatch-thread jprogressbar

我希望让用户了解I / O操作的进度。目前我有一个内部课程,在我启动I / O之前启动,并在完成后停止。它看起来像这样:

class ProgressUpdater implements Runnable {

        private Thread thread;
        private long last = 0;
        private boolean update = true;
        private long size;

        public ProgressUpdater(long size) {
            this.size = size;
            thread = new Thread(this);
        }

        @Override
        public void run() {
            while (update) {
                if (position > last) {
                    last = position;
                    double progress = (double) position / (double) size * 100d;
                    parent.setProgress((int) progress);
                }
            }
        }

        public void start() {
            thread.start();
        }

        public void stop() {
            update = false;
            parent.setProgress(100);
        }
    }

parent是我对UI的引用,position是我外部类中的一个字段,表示我们在I / O中取得的进展。我在停止时将进度设置为100%,因为有时I / O会完成并停止我的更新程序,然后才能完成更新上一个增量。这只能确保它达到100%。

目前,这是有效的,我这样使用它:

ProgressUpdater updater = new ProgressUpdater(file.length());
updater.start();
//do I/O
//...
updater.stop();

问题是循环非常糟糕地占用CPU。我尝试在那里抛出一个锁(带有等待/通知)但我不知道在使用wait / notify时我正在做什么,所以它只是挂了我的线程。我该怎么做才能阻止它使用这么多CPU周期?

2 个答案:

答案 0 :(得分:6)

您应该考虑使用SwingWorker。基本上,你在SwingWorker提供的后台线程上执行所有IO,并且有内置的方法向swing线程报告进度。

然后,无论何时更新该位置,您都可以自动更新进度,而不是连续轮询,这是您迄今为止所做的。

查看Swingworker TimeoutSwingWorker with FileReader,了解是否有任何帮助。

另一种解决方案,如果您不想使用SwingWorker,可能只是通过这样的调用直接更新进度条,而不是更新position值。 :

SwingUtilities.invokeLater(new Runnable() {
    @Override public void run() {
        getMyProgressBar().setValue(position);
    }
});

假设您已设置进度条,以使其最大值为文件大小。

答案 1 :(得分:5)

首先,永远不要使用Thread来更新java中的GUI(Swing组件)。而是使用javax.swing.Timerjavax.swing.SwingWorker。并用于基本I / O操作使用 ProgressMonitorInputStream
作为读取文件并在JTextArea中使用progrressbar显示文件的简单示例。请查看下面给出的代码:

enter image description here

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.io.*;
import java.beans.*;
class ProgressBarFrame extends JFrame 
{
    JProgressBar progressBar;
    int BUFFERSIZE = 10;
    JTextArea textArea;
    MyWorker worker;
    private void createAndShowGUI()
    {
        progressBar = new JProgressBar(0,100);
        progressBar.setStringPainted(true);
        JButton button = new JButton("Read File");
        textArea = new JTextArea(30,100);
        JScrollPane jsp = new JScrollPane(textArea);
        Container c = getContentPane();
        c.add(jsp);
        c.add(progressBar,BorderLayout.NORTH);
        c.add(button,BorderLayout.SOUTH);
        worker = new MyWorker();
        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent evt)
            {
                textArea.setText("");
                progressBar.setValue(0);
                if (worker.getState()== SwingWorker.StateValue.DONE || worker.getState()==SwingWorker.StateValue.STARTED)
                {
                    worker.cancel(true);
                    worker = new MyWorker();
                }
                worker.execute();

            }
        });
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }
    class MyWorker extends SwingWorker<Void, String> 
    {
        MyWorker()
        {
            addPropertyChangeListener(new PropertyChangeListener() 
            {
                public  void propertyChange(PropertyChangeEvent evt) 
                {
                    if ("progress".equals(evt.getPropertyName())) 
                    {
                        progressBar.setValue((Integer)evt.getNewValue());
                    }
                }
            });
        }

        @Override
        public Void doInBackground() throws IOException
        {
            File file = new File("ProgressBarFrame.java");
            long size = file.length();
            long temp = 0;
            BufferedInputStream bfin = new BufferedInputStream(new FileInputStream(file));
            byte[] buffer=new byte[BUFFERSIZE];
            int totalRead = -1;
            while ((totalRead=bfin.read(buffer))!=-1 && ! isCancelled()) 
            {
                temp = temp + totalRead;
                publish(new String(buffer));
                if (bfin.available()<BUFFERSIZE && bfin.available()!= 0)
                buffer = new byte[bfin.available()];
                else if(bfin.available()==0)
                buffer = new byte[1];
                else
                buffer=new byte[BUFFERSIZE];
                setProgress((int)((temp/(float)size) * 100));
                try{Thread.sleep(1);}catch(Exception ex){}
            }
            setProgress(100);
            return null;
        }
        @Override
        protected void process(List<String> chunks) 
        {
            for (String value : chunks) 
            {
                textArea.append(value);
            }
        }
    }
    public static void main(String st[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                ProgressBarFrame pf = new ProgressBarFrame();
                pf.createAndShowGUI();
            }
        });
    }
}