dabadaba
dabadaba

Reputation: 9522

Thread pool not accepting new tasks

I feel like my java concurrency knowledge is getting rusty, I am trying to figure out why the thread pool doesn't accept more tasks in the following code:

ExecutorService e = Executors.newFixedThreadPool(aNumber);

// Task 1
for (int i=0; i<n; i++)
    e.submit(new aRunnable());
while (!e.isTerminated());
System.out.println("Task 1 done");

// Task 2
for (int i=0; i<n; i++)
    e.submit(new anotherRunnable());
while (!e.isTerminated());
System.out.println("Task 2 done");

It never gets to start Task 2, the thread "freezes" when the last task from Task 1 one is run like if it was waiting for something else to finish.

What's wrong?

Upvotes: 0

Views: 368

Answers (2)

Gray
Gray

Reputation: 116888

It never gets to start Task 2, the thread "freezes" when the last task from Task 1 one is run like if it was waiting for something else to finish.

It is waiting. ExecutorService.isTerminated() waits for the thread pool tasks to finish after the pool has been shutdown. Since you've never called e.shutdown(); your loop will spin forever. To quote from the ExecutorService javadocs:

Returns true if all tasks have completed following shut down. Note that isTerminated is never true unless either shutdown or shutdownNow was called first.

You've not shut the service down so that will never be true. In general, anything that spins in a while loop like that is an antipattern – at the very least put a Thread.sleep(10); in the loop. Typically we use e.awaitTermination(...) but again, that's only after you've called e.shutdown();. And you don't want to shut the ExecutorService down because you are going to be submitting more tasks to it.

If you want to wait for all of your tasks to finish then submit more tasks I'd do something like the following and call get() on the Futures that are returned from the first batch of submitting tasks. Something like:

List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < n; i++) {
    futures.add(e.submit(new aRunnable()));
}
// now go back and wait for all of those tasks to finish
for (Future future : futures) {
    future.get();
}
// now you can go forward and submit other tasks to the thread-pool

Upvotes: 5

JVMATL
JVMATL

Reputation: 2122

If you want to know when a specific task finishes, use an ExecutorService, which will return a Future<> (a handle that you can use to get the status of a specific job) -- the executor itself doesn't terminate until you shut it down. Think of an executor like 'batch queue' or a 'coprocessor' waiting around for you to throw some work in the hopper.

Update: Gray answered this much better than I - see his post. -- (how do people type that fast??)

Upvotes: 0

Related Questions