简体   繁体   中英

Why aren't my threads timing out when they fail?

So I asked a question a little while ago: Over here that asked the question "How can I make my threads get killed if they take too long"

I have implemented the solution mentioned there but under certain rare circumstances where a thread times out, the program can still fail / lock up (see: Keep the main() method open, and prevent further cron runs of the program).

Here's the source I'm using:

 //Iterate through the array to submit them into individual running threads.
    ExecutorService threadPool = Executors.newFixedThreadPool(12);
    List<Future<?>> taskList = new ArrayList<Future<?>>();
    for (int i = 0; i < objectArray.length; i++) {
        Future<?> task = threadPool.submit(new ThreadHandler(objectArray[i], i));
        taskList.add(task);
        Thread.sleep(500);
    }

    //Event handler to kill any threads that are running for more than 30 seconds (most threads should only need .25 - 1 second to complete.
    for(Future future : taskList){
        try{
            future.get(30, TimeUnit.SECONDS);
        }catch(CancellationException cx){ System.err.println("Cancellation Exception: "); cx.printStackTrace();
        }catch(ExecutionException ex){ System.err.println("Execution Exception: ");ex.printStackTrace();
        }catch(InterruptedException ix){ System.err.println("Interrupted Exception: ");ix.printStackTrace();
        }catch(TimeoutException ex) {future.cancel(true);}
    }
    threadPool.shutdown();
    threadPool.awaitTermination(60, TimeUnit.SECONDS);

So my question is: with this code implemented, why is the executor service not cutting things off at 30 seconds.

Because I suspect your worker threads are still running. You are calling future.cancel(true); but all that does is set the interrupt flag on the thread -- it does not actively interrupt your running code. Another way to "interrupt" code is to set some volatile boolean shutdown flag to be true and to test for that in your code. See here for more details about interrupting threads .

You need to make sure that your ThreadHandler code handles interrupts correctly. It needs to, for example, check Thread.currentThread().isInterrupted() in loops or in other code blocks. You also need to make sure that you are handling InterruptedException correctly and not just swallowing the interrupt.

See my answer here for more information about thread interrupts.

You have an increasing amount of timeout for each task which may not be intended. Instead you can shutdown the thread pool after you timeout and cancel the rest.

threadPool.shutdown();
threadPool.awaitTermination(30, TimeUnit.SECONDS);
threadPool.shutdownNow(); // interrupt any running tasks.

There is a whole chapter dedicated Task Cancellation in the book Java Concurrency in Practice. From what I've read the task cancellation has to be in the finally block to make sure the task is always ended.

    try{
            future.get(30, TimeUnit.SECONDS);

        } catch (TimeoutException e) {
           // log error message and falls through to finally block
        } catch (ExecutionException e) {
            throw e;
        } finally {
            future.cancel(true); // interrupt task
        }

Interrupted status has to be restored while handling the InterruptedException.

           catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

In the ThreadHandler task check Thread.currentThread().isInterrupted() flag and throw an InterruptedException if true propagating the Interrupt status.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM