Frank
Frank

Reputation: 4417

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.

Upvotes: 1

Views: 3327

Answers (5)

basin
basin

Reputation: 4200

Use case: need to cleanup thread-locals in pool threads upon their completion and this cleanup can take long (e.g. 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);
        }
    }

    ...

Upvotes: 0

user2684301
user2684301

Reputation: 2620

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.

Upvotes: 0

Andrey Chaschev
Andrey Chaschev

Reputation: 16526

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

Upvotes: 1

bstempi
bstempi

Reputation: 2043

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 Futures, 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,

Upvotes: 4

user2161228
user2161228

Reputation:

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.

Upvotes: 0

Related Questions