0

I'm having this odd behaviour. My program hangs eventhough I'm setting a time to force terminate it. could anyone point out what this strange behaviour could be?

here is my code where I start the threads

protected void pendingTaskStarter() throws Exception {
    ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
    ArrayList<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();

    System.out.println("max thread num: " + maxThreadNum);
    for(int i=0;i<maxThreadNum;i++){

        Thread t = new PendingTaskConsumer();
        Future<?> f=service.submit(t);
        futures.add((Future<Runnable>) f);  
    }

    for (Future<?> future:futures) {
        future.get(5l,TimeUnit.MINUTES); // maximum thread's life is 5min (5l <-- 5 in long )
    }   
    service.shutdownNow();

}

I am 100% sure that my program hangs somewhere in PendingTaskConsumer class based on the outputs within PendingTaskConsumer class.

Anyways codes in PendingTaskConsumer should be irrelevant as thread is supposedly forced to be terminated. My question is in what scenraios the following line does not do as its expected.

future.get(5l,TimeUnit.MINUTES);

The program is running on Linux(Ubuntu) and using openjdk-7-jdk backage ( version 1.7)

nafas
  • 5,283
  • 3
  • 29
  • 57
  • How long is the program expected to run for? How long have you waited for it to complete? – Mike Tunnicliffe Mar 13 '15 at 13:33
  • I have an API on top of this layer, where if this program doesn't terminate within 20min, then it reboots the machine that this program is running – nafas Mar 13 '15 at 13:34
  • (1) Why is `PendingTaskConsumer` derived from `Thread`? It is not a thread, but a task that is executed by ANOTHER thread maintained by the `ExecutorService`. (2) is `PendingTaskConsumer()` a method call? If no, it is probalby missing the `new` keyword. – isnot2bad Mar 13 '15 at 20:12
  • @isnot2bad PendingTaskConsumer is class, in the question I missed putting keyword "new" before, – nafas Mar 16 '15 at 09:19
  • @nafas OK. But still you should not derive from `Thread` here! `PendingConsumer` is just a `Runnable` or `Callable`, not a thread by its own! (The threads are managed by the executor _internally_!) – isnot2bad Mar 16 '15 at 09:34
  • @isnot2bad that's interesting mate, PendingConsumer is basically a class that extends Thread, why would you think I shouldn't do this? (ps this is a question, I'm not trying to say you are wrong or anything) – nafas Mar 16 '15 at 09:45
  • @nafas No, it's the other way round: Why _should_ you do this? Your `ExecutorService` wants to have a `Runnable` (or `Callable`), so this is exactly what you should implement. Your code just uses the fact that `Thread` already implements `Runnable`, but it does never start the thread. Just replace `PendingTaskConsumer extends Thread` by `PendingTaskConsumer implements Runnable` and all will be fine (except that it will not solve your actual problem). – isnot2bad Mar 16 '15 at 10:00
  • @nafas see also my answer to http://stackoverflow.com/questions/23990818/executorservice-naming-conventions-java. It also discusses the difference between a thread and a task. – isnot2bad Mar 16 '15 at 10:05
  • @isnot2bad hehe mate, I like the part of comment "(except that it will not solve your actual problem)" . I have changed all my threads to Runnable. I suppose it a good practice that I should start getting used to. – nafas Mar 16 '15 at 10:18

2 Answers2

1

Well... proper exception handling seems to be missing.

/**  
 * Waits if necessary for at most the given time for the computation  
 * to complete, and then retrieves its result, if available.  
 *  
 * @param timeout the maximum time to wait  
 * @param unit the time unit of the timeout argument  
 * @return the computed result  
 * @throws CancellationException if the computation was cancelled  
 * @throws ExecutionException if the computation threw an
 * exception  
 * @throws InterruptedException if the current thread was interrupted
 * while waiting  
 * @throws **TimeoutException if the wait timed out**  
 */  
V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;

If your call to future.get(5l,TimeUnit.MINUTES); expires, then an Exception is thrown and your service is never shut down.

So (one can assume) its internal threads are still running, at least the one that is executing your long running task). Seeing those are non-daemons thread (you'd have to custom the ThreadFactory of your executor for them to be), those pending threads prevent the JVM from shutting down.

If you wish to terminate the tasks forcibly, you can :

  1. design your runnable task to respond to Thread.isInterrupted(), and exit when it sees that become true. (The practical effect of shutdownNow is to set the interrupted flag of your executor's thread )
  2. If you can't (because your are blocked in some library's method that does not listen to interruption), then having a dameon thread seems like the only option.

But anyway, I'd put the executor's shutdown either earlier, or in a finally clause.

GPI
  • 9,088
  • 2
  • 31
  • 38
1

As @GPI already stated in his/her answer, cancellation won't work properly, if your tasks do not repond to thread interruption via Thread.interrupt(). See Oracle: The Java™ Tutorials - Concurrency - Interrupts or Java Executors: how can I stop submitted tasks?.

But even if your tasks do not immediately stop if the thread is interrupted (=the interruption flag is set), you can timeout your method. Just don't listen to task completion by invoking every single get() method of your Futures! That's not necessary as you are not really interested in their result. Just shutdown your ExecutorService and wait for its termination.

protected void pendingTaskStarter() throws InterruptedException {
    ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);

    for (int i = 0; i < maxThreadNum; i++) {
        service.submit(new PendingTaskConsumer());
    }

    // Shutdown service.
    // This will continue to process already submitted tasks.
    service.shutdown();

    try {
        // wait at least 5 minutes for the tasks to complete
        if (!service.awaitTermination(5, TimeUnit.MINUTES)) {
            // still not done yet -> force shutdown
            // this will interrupt currently running tasks.
            service.shutdownNow();
        }
    } catch (InterruptedException ex) {
        // someone interrupted this thread. Shutdown tasks immediately
        service.shutdownNow();
        // propagate exception
        throw ex;
    }
}

So what happens here?

  • First, all tasks are submitted.
  • Then shutdown() is called on the ExecutorService. Note that the service will continue to execute already submitted tasks, but it will not accept new tasks.
  • Now, we wait for the service to terminate by calling awaitTermination with a timeout of 5 minutes. If this method returns true, which means, that the service has terminated within time, everything is fine and we're done. But if it returns false after 5 minutes, it means that the service is still running because there are some tasks that need more time to complete.
  • In that case, we shutdown the service immediately by calling shutdownNow(). Note that this method will not block! It just attempts to cancel all running tasks, usually by interrupting the threads that are currently executing them. This is exactly why your tasks should response to thread interruption properly! If they don't do this, interrupting the thread will have no effect at all!
  • No matter if shutdownNow was successful - we are done and do not wait any longer. So there might still be some tasks that are running because they don't react upon thread interruption (usually because a task is either not implemented properly or it is uninterruptibly on purpose). But we simply don't care.
  • Note the exception handler: When another thread interrupts the thread that is calling our method while it is waiting in method awaitTermination, an InterruptedException is thrown. We handle it by shutting down the service and re-throwing the exception! That is a good thing and makes our method a long-running-operation that is cancellable by itself!
Community
  • 1
  • 1
isnot2bad
  • 24,105
  • 2
  • 29
  • 50
  • it's a very clear explanation. I like the part that you mention there is no point of keeping track of the future. I'll try it and let you know – nafas Mar 16 '15 at 12:27
  • well I'll be damn surprised , it did the trick. I believe **throw ex;** did the trick. even though the threads are not getting terminated. I get out of that method. then once everything else carried out all I needed to do was to add ***System.exit(0);*** to force exit the program. – nafas Mar 16 '15 at 13:25
  • @nafas As I mentioned, the method will terminate after at least 5 minutes no matter if the tasks are running or not. In your case it seems they are still running indeed - that's why the system will not halt without `System.exit(0)`! You should really check your task implementation and ensure, thread interruption is handled properly! – isnot2bad Mar 16 '15 at 15:28
  • `throw ex` is not the important part here as it will only be called if _another_ thread interrupts the current thread. In your case, `awaitTermination` just returns `false` and the method exists after calling `shutdownNow` which seems to have no effect because your tasks ignore the cancellation! – isnot2bad Mar 16 '15 at 15:30
  • I know **System.exit(0)** is a very bad practice. all I wanted to do was to get out of that part of the program(which thanks to your solution I do). once I'm out of that bit, I can talk to mother server. this is an extremely heavy computation which requires ~500 servers. so previously the efficiency was at 60% now the efficiency is at 95% – nafas Mar 16 '15 at 15:41