7

I have a multithreaded implementation where i create an ExecutorService and submit tasks to be executed, i want to know when all the threads is submited have finished without blocking the main thread and the UI. I've tried ExecutorService.awaitTermination() but it blocks the main thread and the UI. I've searched alot but i can't seem to find an elegant way of doing this. I'm currently thinking about creating another thread that counts the amount of threads finished and launches an event when they all finished, but that doesn't to be a good approach and i wanted a better solution!

Gray
  • 115,027
  • 24
  • 293
  • 354
Trota
  • 145
  • 3
  • 9

5 Answers5

7

Use a SwingWorker to shutdown the thread pool and call awaitTermination(). This will prevent the UI from blocking and call done() from the Event Dispatch Thread on your SwingWorker implementation which you can use to trigger the whatever UI changes you need.

If you desire to keep track of the threads running via a UI update you can use the the worker thread to monitor this in a loop and call publish() with arguments which then get passed to your implementation of process() on the EDT.

Dev
  • 11,919
  • 3
  • 40
  • 53
4

Why not use a CountDownLatch and then notify the main thread when the latch has been completed.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    Good idea; there's a nice example cited [here](http://stackoverflow.com/a/3588523/230513). – trashgod Mar 20 '12 at 05:09
  • 1
    @trashgod just commented in your post: the example has a small glitch in accessing the textComponent off the EDT – kleopatra Mar 20 '12 at 11:20
2

You can maintain a separate thread to track when the executor service instance shuts down:

    final ExecutorService execSvc = ...;
    execSvc.submit(task1);
    ...
    execSvc.submit(taskN);
    // important to request the exec service to shut down :)
    execSvc.shutdown();

    new Thread(new Runnable() {

        public void run() {
            while (!execSvc.isTerminated()) {
                try {
                    execSvc.awaitTermination(60, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    // ignore exception
                }
            }
            System.out.println("ExecSvc.run: exec service has terminated!");
            // possibly submit a task using SwingUtilities.invokeLater() to update the UI
        }

    }).start();
shams
  • 3,460
  • 24
  • 24
2

Using CountDownLatch

 

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

and within your task (enclose in try / finally)

 latch.countDown();

Or on ExecutorService you call shutdown() and then awaitTermination()

 
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

Also have a look at THIS answer

Community
  • 1
  • 1
Anuj Kulkarni
  • 2,261
  • 5
  • 32
  • 42
  • 1
    Unless I'm mistaken in my understanding, neither of these solutions are addressing the OP's fundamental question which is to avoid blocking on the main thread. – Trevor Jun 22 '14 at 12:41
2

isTerminated() will do

note however that both awaitTermination and isTerminated will only give you a meaningful result after you have called shutdown

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • I've found some things about isTerminated() but still, i think i need to run it on a "side thread" to constantly check if it returns true which brings me to my initial solution! – Trota Mar 20 '12 at 00:15