ExecutorService, how to wait for all tasks to finish

前端 未结 15 2104
攒了一身酷
攒了一身酷 2020-11-22 15:45

What is the simplest way to to wait for all tasks of ExecutorService to finish? My task is primarily computational, so I just want to run a large number of jobs

相关标签:
15条回答
  • 2020-11-22 16:26

    If you want to wait for all tasks to complete, use the shutdown method instead of wait. Then follow it with awaitTermination.

    Also, you can use Runtime.availableProcessors to get the number of hardware threads so you can initialize your threadpool properly.

    0 讨论(0)
  • 2020-11-22 16:26

    If waiting for all tasks in the ExecutorService to finish isn't precisely your goal, but rather waiting until a specific batch of tasks has completed, you can use a CompletionService — specifically, an ExecutorCompletionService.

    The idea is to create an ExecutorCompletionService wrapping your Executor, submit some known number of tasks through the CompletionService, then draw that same number of results from the completion queue using either take() (which blocks) or poll() (which does not). Once you've drawn all the expected results corresponding to the tasks you submitted, you know they're all done.

    Let me state this one more time, because it's not obvious from the interface: You must know how many things you put into the CompletionService in order to know how many things to try to draw out. This matters especially with the take() method: call it one time too many and it will block your calling thread until some other thread submits another job to the same CompletionService.

    There are some examples showing how to use CompletionService in the book Java Concurrency in Practice.

    0 讨论(0)
  • 2020-11-22 16:27

    I also have the situation that I have a set of documents to be crawled. I start with an initial "seed" document which should be processed, that document contains links to other documents which should also be processed, and so on.

    In my main program, I just want to write something like the following, where Crawler controls a bunch of threads.

    Crawler c = new Crawler();
    c.schedule(seedDocument); 
    c.waitUntilCompletion()
    

    The same situation would happen if I wanted to navigate a tree; i would pop in the root node, the processor for each node would add children to the queue as necessary, and a bunch of threads would process all the nodes in the tree, until there were no more.

    I couldn't find anything in the JVM which I thought was a bit surprising. So I wrote a class ThreadPool which one can either use directly or subclass to add methods suitable for the domain, e.g. schedule(Document). Hope it helps!

    ThreadPool Javadoc | Maven

    0 讨论(0)
  • 2020-11-22 16:27

    A simple alternative to this is to use threads along with join. Refer : Joining Threads

    0 讨论(0)
  • 2020-11-22 16:31

    Root cause for IllegalMonitorStateException:

    Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

    From your code, you have just called wait() on ExecutorService without owning the lock.

    Below code will fix IllegalMonitorStateException

    try 
    {
        synchronized(es){
            es.wait(); // Add some condition before you call wait()
        }
    } 
    

    Follow one of below approaches to wait for completion of all tasks, which have been submitted to ExecutorService.

    1. Iterate through all Future tasks from submit on ExecutorService and check the status with blocking call get() on Future object

    2. Using invokeAll on ExecutorService

    3. Using CountDownLatch

    4. Using ForkJoinPool or newWorkStealingPool of Executors(since java 8)

    5. Shutdown the pool as recommended in oracle documentation page

      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();
      }
      

      If you want to gracefully wait for all tasks for completion when you are using option 5 instead of options 1 to 4, change

      if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      

      to

      a while(condition) which checks for every 1 minute.

    0 讨论(0)
  • 2020-11-22 16:33

    You could wait jobs to finish on a certain interval:

    int maxSecondsPerComputeDTask = 20;
    try {
        while (!es.awaitTermination(uniquePhrases.size() * maxSecondsPerComputeDTask, TimeUnit.SECONDS)) {
            // consider giving up with a 'break' statement under certain conditions
        }
    } catch (InterruptedException e) {
        throw new RuntimeException(e);    
    }
    

    Or you could use ExecutorService.submit(Runnable) and collect the Future objects that it returns and call get() on each in turn to wait for them to finish.

    ExecutorService es = Executors.newFixedThreadPool(2);
    Collection<Future<?>> futures = new LinkedList<<Future<?>>();
    for (DataTable singleTable : uniquePhrases) {
        futures.add(es.submit(new ComputeDTask(singleTable)));
    }
    for (Future<?> future : futures) {
       try {
           future.get();
       } catch (InterruptedException e) {
           throw new RuntimeException(e);
       } catch (ExecutionException e) {
           throw new RuntimeException(e);
       }
    }
    

    InterruptedException is extremely important to handle properly. It is what lets you or the users of your library terminate a long process safely.

    0 讨论(0)
提交回复
热议问题