How to correctly use ExecutorService to manage the number of SwingWorkers simultaneously?

advertisements

I am generating SwingWorkers based on a number of connections I need to make. I am trying to make it so that I set a fixed number of maximum concurrant SwingWorkers and when one of those finishes another one is started (or many others are started if many have finished). Based on http://java.dzone.com/articles/multi-threading-java-swing I am setting up the basic SwingWorker like this:

SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
        @Override
        protected Boolean doInBackground() throws Exception {

                        System.out.println("One SwingWorker just ran! ");
                }

                return true;
        }

        // Can safely update the GUI from this method.
        protected void done() {

                boolean status;
                try {
                        // Retrieve the return value of doInBackground.
                        status = get();
                        statusLabel.setText("Completed with status: " + status);
                } catch (InterruptedException e) {
                // This is thrown if the thread's interrupted.
                } catch (ExecutionException e) {
                // This is thrown if we throw an exception
                // from doInBackground.
                }
        }

};

worker.execute();

Now I'm uncertain in how to implement the mechanism I described above.

From https://stackoverflow.com/a/8356896/988591 I saw that I can use an ExecutorService to execute instances of SwingWorker and that this interface also allows to set the number of threads:

int n = 20; // Maximum number of threads
ExecutorService threadPool = Executors.newFixedThreadPool(n);
SwingWorker w; //don*t forget to initialize
threadPool.submit(w);

I think this is what I need but I don't know how to put the whole thing together (..I am also quite new to Java..). Could someone guide me a bit in the process of implementing this? Say at the top I have int totalTask = 100; Maybe it's just a matter of some loops but I can't seem to find any really easy-to-follow examples around and I just can't totally wrap my mind around it yet so.. I would appreciate some help! Thanks.


UPDATE: I have set up the ExecutorService this way:

ExecutorService executorService = Executors.newFixedThreadPool(500);

for (int i = 0; i < 20 ; i++) {

    executorService.submit(worker);
    //I tried both...
    //executorService.execute(worker);
}

and I have removed worker.execute() called after the SwingWorker above but the output from console is just a single "One SwingWorker just ran!" line, how is that ? What did I do wrong?


You'd do something like this:

  • Initiate the executorservice using a fixed threadPool as you have shown.
  • In a loop create your runnable. As many runnables as you need.
  • You can have 50 threads and 5000 runnables. After the 1st 50
    runnables, whichever thread is free will pick up the 51st task, and
    so on.
  • Call the executorservice's execute method with your Runnable.
  • Once all are done, you shutdown the executor service.

Like this:

ExecutorService executorService = Executors.newFixedThreadPool(500);

for (long i = 0; i < 1000000; i++) {
    Runnable populator = new YourRunnable();
    executorService.execute(populator);
}
executorService.shutdown();
while(!executorService.isTerminated()){
}

That isTerminated can be used to check whether the executorServices is actually down. Since you can have several executor threads running even after you call the shutdown() method (because they haven't completed the task yet), that while loop acts like a wait call.

And one key thing: whatever you want to pass to the ExecutorService, it must be a Runnable implementation. In your case, your SwingWorker must be a Runnable.