Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do my SwingWorker threads keep running even though they are done executing?

I'm implementing a GUI for a console application, and I need to do some actions (for example, parse an XML file) in a specified time interval. I decided to use javax.swing.Timer alongside SwingWorker to be sure that these actions will not make my application unresponsive.

I had implemented the timer this way:

public class DataUpdateTimer extends Timer {

    private String dataFlowControllerXML = null;
    private DataUpdateWorker dataUpdateWorker = null;

    public class DataUpdateWorker extends SwingWorker {

        private String dataFlowControllerXML = null;

        DataUpdateWorker(String dataFlowControllerXML) {
            super();
            this.dataFlowControllerXML = dataFlowControllerXML;
        }

        @Override
        protected Boolean doInBackground() throws Exception {

            Thread.sleep(300);
            return Boolean.TRUE;
        }

    }

    public class DataUpdateIntervalListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            DataUpdateTimer timer = (DataUpdateTimer)e.getSource();
            DataUpdateWorker dataUpdateWorker = timer.getDataUpdateWorker();

            if (dataUpdateWorker != null)
                if (dataUpdateWorker.isDone()) {
                    Boolean updateResult = Boolean.FALSE;
                    try {
                        updateResult = (Boolean)dataUpdateWorker.get();
                    } catch (InterruptedException ex) {

                    } catch (ExecutionException ex) {

                    }

                    dataUpdateWorker = null;
                }

            // Creating new worker thread here
            if (dataUpdateWorker == null) {
                timer.dataUpdateWorker = new DataUpdateWorker(timer.dataFlowControllerXML);

                // Starting a new worker thread for parsing Data Flow Controller's XML
                timer.dataUpdateWorker.execute();
                return;
            }
        }
    }

    DataUpdateTimer(Integer dataUpdateInterval, String dataFlowControllerXML) {

        super(dataUpdateInterval.intValue(), null);
        this.dataFlowControllerXML = dataFlowControllerXML;
        addActionListener(new DataUpdateIntervalListener());
    }

    @Override
    public void stop() {
        super.stop();
        if (dataUpdateWorker != null) {
            if (!dataUpdateWorker.isDone() || !dataUpdateWorker.isCancelled())
                dataUpdateWorker.cancel(true);
        }
    }
}

...and use it as follows:

new DataUpdateTimer(1000, dataFlowControllerXML).start();

Everything works as I wish. Timer creates new a SwingWorker instance and executes it. After the worker is done, the new one is created and executed.

The thing I'm confused by is that after the worker's thread is done I still can see it running in Netbeans' debugging window (for example, as SwingWorker-pool-3-thread-1) or in Windows Task Manager (the number of running threads doesn't decrease after the thread is done). The number of SwingWorker threads is limited to 10, but having them running embarrasses me.

In the case of simple thread usage:

Thread th = new Thread(new Runnable() {

    public void run() {
        int a = 0;
    }
});
th.start();

This thread automatically disappears after execution.

Is this SwingWorker behavior normal?

like image 965
ezze Avatar asked Mar 01 '11 15:03

ezze


Video Answer


1 Answers

Yes, this is normal. As the thread's name suggests, the swing workers' model (background) actions are being delegated to a thread pool. When the work is done the thread is returned to the pool so another worker can use it. This eliminates some overhead in creating/destroying threads which can be expensive.

By the way, the background threads won't stick around forever. Looking at the source for SwingWorker I see:

//from SwingWorker.java (c) Sun Microsystems/Oracle 2009
executorService =
            new ThreadPoolExecutor(1, MAX_WORKER_THREADS,
                                   10L, TimeUnit.MINUTES,
                                   new LinkedBlockingQueue<Runnable>(),
                                   threadFactory);

This indicates that the threads will die off after being idle for 10 minutes.

like image 172
Mark Peters Avatar answered Nov 15 '22 14:11

Mark Peters