ICanCYou ICanCYou - 3 months ago 21
Java Question

ScheduledThreadPoolExecutor only runs Swingworker once

ScheduledThreadPoolExecutor (which implements ScheduledExecutorService) seems to be only running the SwingWorker class once when using the ScheduleAtFixedRate method. The original code is kinda long, so I made a new code that produces the same results below.

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class ScheduledThreadPoolExecutorTest extends SwingWorker<Void, Void>{
@Override
protected Void doInBackground() {
System.out.println("Yay!");
return null;
}

@Override
protected void done() {
try {
get();
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("Woohoo!");
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.scheduleAtFixedRate(new ScheduledThreadPoolExecutorTest(), 0, 30, TimeUnit.MILLISECONDS);
}
});
}
}


This yields the results:

Yay!
Woohoo!


Why is ScheduledThreadPoolExecutor running SwingWorker only once? And what can I do to make the SwingWorker run every 30 milliseconds as indicated in the code?

Answer

While SwingWorker does implement the Runnable interface, per its API section on the doInBackground() method:

Note that this method is executed only once.

So while its inner run() method may repeatedly run, the doInBackground() will only run once. Not only that, but the run() method is marked final within SwingWorker, and so you can't override it to call doInBackground multiple times.

A better solution is not use a SwingWorker at all but rather a simpler Runnable-derived class.