Reputation: 4417
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
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
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
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
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 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,
Upvotes: 4
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