- No - This is the incorrect approach if you want to control the number of threads yourself. Why? Because if you look at the
SwingWorker
code you'll see that it uses a ThreadPoolExecutor
internally containing a maximum of 10 threads. If you kick off a number of SwingWorker
's concurrently they will all run using this executor. However, you have no direct control over whether the background threads are executed in parallel.
- See point 1.
My recommended solution would be:
- Create a single
SwingWorker
.
- Within the
doInBackground()
method kick off 10 threads either directly or by using an ExecutorService
.
- Use a
CountDownLatch
or CompletionService
to synchronize between your master thread (i.e. SwingWorker
background thread) and worker threads.
Example
Define the number of worker threads to invoke and declare the JLabel to be updated.
final int nThreads = 10;
JLabel myLbl = new JLabel();
Define the unit of work we wish to execute as a Callable<String>
. The String
result will be used to update the JLabel
.
private static class MyCallable implements Callable<String> {
public String call() { ... }
}
Now kick off a SwingWorker
, which will in turn kick off multiple parallel workers to do any processing. The worker will not return a result via the call to done()
(hence the Void
type) but will marshall intermediate String
results back onto the Swing thread by calling process(String... chunks)
.
new SwingWorker<Void, String>() {
// See method definitions below.
}.execute();
Define doInBackground()
to kick off the worker threads and block for each result using a CompletionService
.
public Void doInBackground() throws Exception {
// Define executor service containing exactly nThreads threads.
ExecutorService execService = Executors.newFixedThreadPool(nThreads);
// Define completion service that will contain the processing results.
CompletionService compService = new ExecutorCompletionService(execService);
// Submit work to thread pool using the CompletionService. Future<String>
// instances will be added to the completion service's internal queue until complete.
for (int i=0; i<nThreads; ++i) {
compService.submit(new MyCallable());
}
// Take results from each worker as they appear and publish back to Swing thread.
String result;
while ((result = compService.take().get()) != null) {
publish(result);
}
}
Now we implement process(String... chunks)
to simply update the JLabel
when called.
public void process(String... chunks) {
if (chunks.length > 0) {
// Update label with last value in chunks in case multiple results arrive together.
myLbl.setText(chunks[chunks.length - 1]);
}
}
Finally we override done()
to marshall any exceptions back onto the Swing thread.
public void done() {
try {
get(); // Will return null (as per Void type) but will also propagate exceptions.
} catch(Exception ex) {
JOptionPane.show ... // Show error in dialog.
}
}