Java wait for all threads to complete before printing some information

Viewed 435

I am using threads in java to read file and print certain items to console. I am reading more than 5 files in a loop, and at the end of the loop I want to print a message.

So:

   for (int i = 1; i < args.length; i++){
      String filename = args[i]; //this will contain each filename
      // your code goes here
      new processFile(filename,counter).start();
      
   }

   System.out.print(counter.numerOfMatches)

I looked for solution online but almost all suggests using join(). Does that not defeat the purpose of using threads. Is there not a way to run all of the fileProcessing threads parallelly without one having to wait for the another and then somehow figure out when all of the processes finishes before moving to the final line?

3 Answers

Use a CountDownLatch: initialize it with the number of threads, then have each thread count down the latch when it's done. The main thread awaits the latch.

Something like this:

CountDownLatch latch = new CountDownLatch(args.length);
for (int i = 1; i < args.length; i++){
    String filename = args[i];
    new processFile(latch, filename, counter).start();
}

latch.await();
System.out.print(counter.numerOfMatches)

Each of your threads needs to see the latch, for example by passing it in the constructor. When the thread is done, it notifies / counts down the latch.

@Override
public void run() {
    // do actual work, then signal we're done:
    latch.countDown();
}

join() is meant precisely for tasks for which you must wait for all the threads to finish their work in order to continue. If all you want to do is print a message when all the threads finish some task and be able to move on with the threads that already finished you don't need join(). You can, for example, start some kind of a Counter (Semaphore) class, increment 1 every time a thread finishes, and when it reaches the number of threads you had it will print your message. Simply make the print a part of the addition function.

You can definitely use ExecutorService with newFixedThreadPool which will run asynchronously to process each task.

ExecutorService executors = Executors.newFixedThreadPool (<<Number_of_Threads>>);
CompletionService<String> completionService = new ExecutorCompletionService<>(executors);

List<Future<String>> futures = new ArrayList<> (  );
for (int i=0; i<inp; i++) {
    futures.add (  completionService.submit ( new WorkerThread ("ThreadName-"+i) ));
}
Related