Frank
Frank

Reputation: 31086

What is the right way to use Java executor?

I am using Java executor in the following way, but not sure if every line is necessary and if this is the correct way to use it :

  ExecutorService executor=Executors.newFixedThreadPool(30);
...
  int N=200;
  CountDownLatch doneSignal=new CountDownLatch(N);
  for (int i=0;i<N;i++) executor.execute(new Test_Runner(doneSignal,...));
  doneSignal.await();
  executor.shutdown();
  while (!executor.isTerminated()) { Thread.sleep(1000); }
  // Blocks until all tasks have completed execution after a shutdown request
  executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
...

class Test_Runner implements Runnable
{
  private CountDownLatch doneSignal;
  Thread Test_Runner_Thread;

  public Tes_Runner(CountDownLatch doneSignal,...)
  {
    this.doneSignal=doneSignal;
  }

// Define some methods

  public void run()
  {
    try
    {
//      do some work
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    doneSignal.countDown();
  }

  public void start()
  {
    if (Test_Runner_Thread==null)
    {
      Test_Runner_Thread=new Thread(this);
      Test_Runner_Thread.setPriority(Thread.NORM_PRIORITY);
      Test_Runner_Thread.start();
    }
  }

  public void stop() { if (Test_Runner_Thread!=null) Test_Runner_Thread=null; }
}

Upvotes: 1

Views: 841

Answers (2)

Ravindra babu
Ravindra babu

Reputation: 38910

You can further simplify the code.

  1. You can remove CountDownLatch.
  2. Change Test_Runner to Callable task.
  3. Create a ArrayList of Callable Tasks.

      List<Test_Runner> callables = new ArrayList<Test_Runner>();
      for (int i=0;i<N;i++) {
         callables.add(new Test_Runner());
      }
    
  4. Use invokeAll() on executorService.

    List<Future<String>> futures = executorService.invokeAll(callables);
    

From javadocs,

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
                          throws InterruptedException

Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.

And you can shutdown executorService as proposed by Jose Martinez

Relate SE question : How to shutdown an ExecutorService?

Upvotes: 1

Jose Martinez
Jose Martinez

Reputation: 11992

Looks correct to me. In the past I have followed the suggested implementation from the Java 7 JavaDoc for ExecutorService for stopping it. You can get it fromt he Java 7 Javadoc but I provide it below for convenience. Edit it to fit your needs, for example you might want to pass the number of seconds to wait. The good thing about using a CountDownLatch is that by the time it is done waiting you know the ExecutorService will terminate right away. Also, you might want to add a timeout to your latch's await if needed in future real world cases. Also, put your latch.countDOwn() in a try's finally block when using in real world application.

 void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }

Upvotes: 1

Related Questions