简体   繁体   中英

How can I tell that threads in ThreadPoolExecutor are done?

I am writing code where I need to make sure that no threads are currently running in a thread pool before I commit results (to avoid losing data I should have put in the commit). For that, I'm using:

while (_executor.getActiveCount() > 0)
{
  try
  {
    Thread.sleep(10); // milliseconds
  }
  catch (InterruptedException e)
  {
    // OK do nothing
  }
}

But a colleague pointed out in review that the doc for getActiveCount states:

  • Returns the approximate number of threads that are actively
  • executing tasks.

So, is there a risk I would get out of the while loop while there are still active threads in the pool? If so, what would be the correct way to wait for all my worker threads to be done?

Edit: To give some more context : this is an online system, where the task that contains the executor service is left running indefinitely. Work comes in via a messaging system, is put on a thread in the executor, which doesn't need any synchronization, and works come out into another queue for the messaging system. I don't want to kill the executor to wait for completion of tasks.

You might want to consider using a CompletionService ( http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CompletionService.html ).

A CompletionService wraps an ExecutorService and returns a Future when tasks are submitted. By maintaining a list of these Future s, you can see if the jobs that you're waiting on have completed. It also has the additional advantage that you can have others use the same ExecutorService since you have some means of accounting,

_executor.awaitTermination(); should do the job. Now, it won't actually wait for the threads to shutdown, but rather it would wait for all available tasks to terminate.

You could also provide keepAliveTime to a thread pool constructor to instantly terminate idle threads:

ExecutorService executor = new ThreadPoolExecutor(0, 10, 0L /* keepAlive */, 
        TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

To notify a thread that it should clean up and terminate, use the interrupt method. t.interrupt();

and it is good to print or have log of your errors from catch block.

When tasks are submitted to the executor, they return Futures, which indicate when they complete. That is the preferred mechanism to use.

You can use JDK ExecutorService shutdown/awaitTermination.

Use case: need to cleanup thread-locals in pool threads upon their completion and this cleanup can take long (eg connection close). Only after that the main thread can continue.

A worker thread can register itself in some collection. For that override start() and run() and pass a custom thread factory to ThreadPoolExecutor :

class MyThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(final Runnable r) {
        return new MyThread(r);
    }
...

class Some {
    void waitAllThreads() {
        Thread worker;
        while ((worker = workerThreads.poll()) != null) {
            worker.join();
        }
    }
    ...

class MyThread extends Thread {

    @Override
    public synchronized void start() {
        if (getState() == State.NEW) {
            some.workerThreads.offer(this);
        }
        super.start();
    }

    @Override
    public void run() {
        try {
            super.run();
        } finally {
            some.workerThreads.remove(this);
        }
    }

    ...

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