A1+A2.
Yatendra, is it necessary that your Main SwingWorker
must be the only one that passes interim results to the EDT
? If your tasks were also SwingWorker
instances, the Main Worker could delegate the responsability of sending interim results back to the EDT
to them and just take care of the TaskWorkers
life-cycle.
package threading;
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
class MainSwingWorker extends SwingWorker<Void, Void> {
private List<TaskWorker> tasks;
public MainSwingWorker() {
tasks = new LinkedList<TaskWorker>();
for(int i=0; i<2; i++)
tasks.add(new TaskWorker(i));
}
@Override
public Void doInBackground() throws Exception {
Test.log("Building tasks.");
for(TaskWorker task : tasks)
launch(task);
Test.log("Waiting 5 secs.");
Thread.sleep(5000);
Test.log("Cancelling tasks");
for(TaskWorker task : tasks )
task.cancel(true);
return null;
}
private void launch(final TaskWorker task) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test.log("Launching task worker.");
task.execute();
}
});
}
}
class TaskWorker extends SwingWorker<Void, String> {
private int id;
public TaskWorker(int wid) {
id = wid;
}
@Override
public Void doInBackground() throws Exception {
System.out.format("[%s] Starting worker %s\n", Thread.currentThread().getName(), id );
while( !isCancelled() ) {
// ***************************
// your task process code here
// ***************************
publish(String.format("A dummy interim result #%s", id));
Thread.sleep(1000);
}
return null;
}
@Override
public void process(List<String> results) {
// it's pretty obvious, that once this method gets called you can safely
// call the Swing API from EDT among with the interim results
for(String result : results )
Test.log(result);
}
}
public class Test {
public static void log(String msg) {
System.out.format("[%s] %s\n", Thread.currentThread().getName(), msg);
}
public static void main(String[] args) throws Exception {
log("Init.");
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
log("Starting main worker.");
MainSwingWorker worker = new MainSwingWorker();
worker.execute();
}
});
Thread.sleep(7000);
log("Finished.");
}
}
Keep mind that this is just a test, I know that there are a few ugly Thread.sleep(long)
calls.
[main] Init.
[AWT-EventQueue-0] Starting main worker.
[SwingWorker-pool-1-thread-1] Building tasks.
[SwingWorker-pool-1-thread-1] Waiting 5 secs.
[AWT-EventQueue-0] Launching task worker.
[AWT-EventQueue-0] Launching task worker.
[SwingWorker-pool-1-thread-2] Starting worker 0
[SwingWorker-pool-1-thread-3] Starting worker 1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[SwingWorker-pool-1-thread-1] Cancelling tasks
[main] Finished.
A3
But if having another ExecutorService
to schedule your task execution is a requirement in your project, I would implement a similar publish-process mechanism to perform communication between your Main Swing Worker Thread and that Task Thread. Although it seems to be repetitive, You may use a java.concurrent.ConcurrentQueue
to store interim results as they become available?
PS: I just noticed a few days ago, but there is an annoying bug around SwingWorkers that prevents its ExecutorService from caching unused threads.