user9549355
user9549355

Reputation: 97

ExecutorService not terminating in time

I have an ExecutorService that runs a few threads.

What I am trying to accomplish is to execute, and then wait for all threads to terminate. To give you more background, every thread1 connects to a website.

This is what I came up with:

public static void terminateExecutor(ExecutorService taskExecutor) {

        taskExecutor.shutdown();
        try {
          taskExecutor.awaitTermination(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            System.out.println("Some tasks were interrupted!"); //This gets printed
        }
    }

Now, strangely enough, the main thread that uses the ExecutorService terminates, but the thread1s in it don't.

I noticed this because thread1 threw an error (the main thread at this point was already dead) telling me that it didn't find the URL specified (so I guess it's something related to connections).

Is it possible that awaitTermination doesn't terminate the thread1 because its trying (and retrying it seems) to connect to an invalid link?

I cannot stop the thread1 in any other way (or at least to my knowledge I can't), because there isn't any kind of loop.

EDIT:

I get thread1 by creating a new class and feeding it to the executor.

for (....)
    {

        String urlToVisit = globalUrl + links.get(i);
        Thread thread1 = new MagicalThread(urlToVisit, 2).getThread();
        executor.execute(thread1);

    }
    terminateExecutor(executor.getExecutor());

Upvotes: 2

Views: 1337

Answers (3)

Nathan Hughes
Nathan Hughes

Reputation: 96444

The executor uses interruption to let the threads know it's time to quit. If your tasks are using blocking I/O then they will be blocked and can't check the interrupt flag. There is no ability for the blocked task to respond to the interruption in the way that happens with sleep or wait, where interruption causes the threads to wake up and throw an InterruptedException.

If you set a timeout on the socket then, once the socket times out, the task can check for interruption. Also you can have the task respond to interrupt by closing the socket. See https://www.javaspecialists.eu/archive/Issue056.html

Be aware that implementing this in a threadpool is more involved than in the example given in the linked article. Nothing about the executor lets the pool call methods on a task besides run. One way to do it would be to put a reference to the socket in a ThreadLocal. Then you could make a ThreadFactory for the pool to use to subclass Thread with a method that overrides the interrupt method on the thread to get the socket from the ThreadLocal and close it.

Upvotes: 0

Andy Turner
Andy Turner

Reputation: 140524

When

taskExecutor.awaitTermination(2, TimeUnit.SECONDS);

returns, it doesn't guarantee that the ExecutorService has terminated. Look at its return value:

[Returns] true if this executor terminated and false if the timeout elapsed before termination

You don't check this value, but I'll bet it's returning false if the thing you're running in the ExecutorService is still running.

Upvotes: 0

Joe C
Joe C

Reputation: 15714

From the Javadoc (emphasis mine):

Blocks until all tasks have completed execution after a shutdown request

You need to call shutdown() before calling awaitTermination, otherwise it does nothing meaningful.

Upvotes: 2

Related Questions