1

My Swing application has a table which is populated when some data are fetched from an external source. To display data I'm using SwingWorker thread which is called from the thread that is supposed to fetch the data in this way:

 // SwingWorker Thread
 private class DisplayRowsTask extends SwingWorker<Void, Object[]> {

    private Vector<String[]> _data;

    @Override
    protected Void doInBackground() {
        while (_continue && !hasError()) {
            // some logic to fetch and place data in _data
            // data adjustment
            for (String[] row : _data) publish (row);
            _data = new Vector<String[]>();
        }
        return null;
    }

    @Override
    protected void process(List<Object[]> rows) {
        for (Object[] row : rows) ((DefaultTableModel)_table.getModel()).addRow(row);
    }
}

The results displayed are correct and everything works fine apart that the CPU usage is 100% (and over!) especially in the situation where a lot of data are fetched frequently. How can I limit this usage?

Another question maybe not fully related: how can I know if the data are been displayed in the table? The method "SwingWorker.isDone()" doesn't give this information

Randomize
  • 8,651
  • 18
  • 78
  • 133
  • 2
    You really should re-read SwingWorker's documentation. The main thread shouldn't have to loop and create several instances of SwingWorker. The SwingWorker should loop and incrementally and asynchronously populate the table. It's the background thread that must fetch the data, and not the main thread. – JB Nizet Jan 15 '12 at 10:54
  • Thanks I have re-edited my code but I still have 100% CPU. – Randomize Jan 15 '12 at 11:29
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jan 15 '12 at 11:39
  • When do you stop the loop? If the background thread loops endlessly, of course you'll have 100% CPU usage. – JB Nizet Jan 15 '12 at 12:00
  • @JB Nizet stupid question ---> I think that not possible take CPU at 100% with one single thread on todays PC, or am I wrong ??? – mKorbel Jan 15 '12 at 12:25
  • the loop is endless as there is no way to get some "notify" from the source of data unless continuously "query" it. – Randomize Jan 15 '12 at 12:28
  • @mKorbel: if the computer has 2 cores, and one background thread loops continuously, without doing any IO, and publishes results continuously to the EDT, which runs on the other core, at each iteration, then I don't see why the CPU wouldn't be at 100%. If the CPU has just one core, it's even easier to reach 100%. – JB Nizet Jan 15 '12 at 12:33
  • @JB Nizet I needed confirm my view, now that make me sence, thanks – mKorbel Jan 15 '12 at 12:43
  • I have used JProfiler and "CPU Views" returns SwingWorker.run ~50% and EventDispatchThread.run ~50%. Maybe "addRow(...)" on the table is the problem? – Randomize Jan 15 '12 at 14:20
  • @Randomize are you update all Cells including those that aren't visible in the JViewport ??? – mKorbel Jan 15 '12 at 15:01
  • @mKorbel I missed a "TableModelListener" which acted on JViewport. I moved its operation inside SwingWorker.process(..) and now CPU usage is dropper down to 30-40% (that I suppose is acceptable). Anyway I noticed when a "RowFilter" is applied to the table CPU usage is still (and over) 100%. Has any sense apply RowFilter inside SwingWorker.process(...)? – Randomize Jan 15 '12 at 16:46

2 Answers2

1

Your CPU is going up to 100% naturally, because you're idly looping while (!task.isDone()); in run(). SwingWorker is executed asynchronously by calling execute(); so you don't have to execute it in a Thread. You shouldn't use Thread anyway in Swing. The SwingWorker does the job. It has hook methods to invoke code when it's finished. If you have many tasks to execute implement them in the SwingWorker itself.

Something like this:

   @Override
    protected Void doInBackground() {
      while (_continue && !hasError()) {
        // do some adjustments around _data
        for (String[] row : _data) publish (row);
       }
       return null;
    }

To another question: I think addRow(...) fires event. Your table should get this event and invalidate component. If you want to execute code after SwingWorker is done, then override done() method.

viktor
  • 1,277
  • 10
  • 16
1

not answer ....

not idea what did you tried because I not able to generating 100% CPU usage by implements Essential Java correctly, if you are IDE user then you can profile your code with built-in JProfiler, then there you can see all important events from current JVM, however basically you have three choises

1) implements Executor & SwingWorker, notice about take error from Future

2) by wrapping your methods to the Runnable#Thread, notice output to the GUI must be wraped into invokeLater,

3) create some ThreadFactory or implements Executor, notice output to the GUI must be wraped into invokeLater in some cases required into invokeAndWait

4) you can simulating/compare with performace issues Christmas Tree Applications

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319