简体   繁体   中英

Design pattern for returning responses from child threads

I am looking for a design pattern where the parent thread will spawn multiple child threads. Each child thread will perform some computation and return an appropriate result.

The parent thread will be waiting for the child threads to complete. After all child threads are completed, the consolidated result will be sent to the parent thread.

The parent thread will then proceed with consolidated result.

Check the join method of Thread class. Here is a working sample:

import java.lang.*;

public class Threads {

 public void callChildren() throws Exception {

   Thread t = new Thread(new ChildThread());
   t.start();
   t.join();
   System.out.print(t.getName());
   System.out.println(", status = " + t.isAlive());
  }

   public static void main(String[] args) throws Exception{

        for(int i = 0 ; i < 4; i ++) {
            new Threads().callChildren();
         }

         System.out.println("Printing from Parent thread after all child thread are complete.");
   }


  private class ChildThread implements Runnable{

    @Override
    public void run() {
        System.out.println("Thread started:::"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread ended:::"+Thread.currentThread().getName());
    }
   }

} 

Some existing answers recommend spawning threads manually -- I would not do that, but rather use an ExecutorService instead.

If you are allowed to use a 3rd party library, Guava will do the trick: Submitting your child tasks to a ListeningExecutorService will give you back a ListenableFuture<T> (with T being your result type). You can then eg use Futures.allAsList to combine all child task futures into one future (encapsulating the list of result values). If you then wait on this one future (with get ), you effectively wait on all child tasks. Once it completes, you can consolidate all result values and continue with your parent logic.

Here's a very minimal example:

public class Example {

    private static final int NUMBER_OF_CHILD_TASKS = 5;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executorService);

        List<ListenableFuture<String>> childTaskFutures = IntStream.range(0, NUMBER_OF_CHILD_TASKS).mapToObj(
                taskIndex -> listeningExecutorService.submit(new ChildTask(taskIndex))
        ).collect(Collectors.toList());

        ListenableFuture<List<String>> parentFuture = Futures.allAsList(childTaskFutures);
        try {
            List<String> results = parentFuture.get();
            results.forEach(System.out::println);
        } catch (Exception e) {
            // proper handling...
        }
    }

    private static final class ChildTask implements Callable<String> {

        private final String taskName;

        private ChildTask(int taskIndex) {
            this.taskName = "Task " + taskIndex;
        }

        @Override
        public String call() throws Exception {
            System.out.println(taskName + " executing...");
            Thread.sleep(1000);
            return "Result of " + taskName;
        }
    }

}

If you can't use a 3rd party library, you can use a "traditional" ExecutorService to spawn the child tasks and use an ExecutorCompletionService to process the resulting futures. The linked javadocs give examples for both aspects of the problem.

Threads cannot return a result. Child threads can communicate with the creating thread when the creator passes a reference to itself ("this") to the created threads, such as:

MyThread thd1 = new MyThread(this, latch);

The latch is a reference to a CountDownLatch. The creator also has a method that the created thread will call when it completes, such as:

public void saveResult1 (Object something) {

  object1 = something;
  latch.countDown();

}

The creator simply waits for all threads to finish with an await.

try {
    latch.await();
  } catch (InterruptedException ignore) {}

When each created thread finishes its work it can call method saveResult... on the creator thread that saves the result somewhere and does a count down.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM