7

If the method call takes more than 10 seconds I want to kill it and move on.

Is multi-threading my only option to solve this problem?

If I go with multi-threading which I'm very new at, my run method would only contain the one method as follows. If myMethod() gets stuck in an infinite loop is there a way to interrupt this thread?

public void run() {
    myMethod();
}

Let's assume myMethod() is the following and changing it is not an option.

while(true){
    System.out.println("Thinking.");
        for (int i = 0; i < 100000; i++) {
            //wasting time
        }
}

I was going for Mik378's solution, but I don't think this will work as myMethod doesn't throw the InterruptedException exception.

Dale
  • 1,289
  • 3
  • 16
  • 36
  • http://stackoverflow.com/questions/8982388/how-can-i-brutally-and-mercilessly-abort-a-task-in-java – bonCodigo Dec 06 '12 at 16:49
  • 1
    Just being pedantic: you cannot know if you are stuck in an infinite loop anyway without any knowledge on `myMethod()` (it is known as [The Halting Problem](http://en.wikipedia.org/wiki/Halting_problem)), but killing after some predefined time has passed is definetly possible (at least theoretically) – amit Dec 06 '12 at 16:50

4 Answers4

7

Using threads to achieve this is tricky. There is no portable and safe method to kill a thread without cooperation from said thread. For further details, see How do you kill a thread in Java? and Why are Thread.stop [et al] deprecated?

A more robust approach is to call the method in the context of a separate process, and kill that process.

An even better approach is to understand why things are getting stuck in the first place, and figure out a way to prevent them from getting stuck (or a way to have a timeout and throw an exception etc). Whether that's a realistic possibility in your case, I don't know.

Community
  • 1
  • 1
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Also highly relevant from the linked question: http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html – Brian Dec 06 '12 at 16:54
  • just curious: why doesn't the `Runnable` interface mandate a `killThread` method as a matter of courteous convenience to be able to back out of the thread invocation? – amphibient Dec 06 '12 at 16:54
  • 1
    @foampile Because there are multiple *better* ways of doing it, e.g. catching interruption exceptions, checking `Thread.interrupted`, using a `volatile` signal variable. Plus, not every runnable is necessarily invoked in a new thread. – Brian Dec 06 '12 at 16:55
  • a `killThread` could be dangerous, since it wouldn't allow to clean resources properly before thread dies. – Mik378 Dec 06 '12 at 17:24
  • @NPE After some research I'm still not clear on how to do this " call the method in the context of a separate process". Could you expound? – Dale Dec 06 '12 at 21:21
  • 1
    @Dale Possibly something like: http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec%28java.lang.String%29 – assylias Dec 06 '12 at 21:33
2

You can start a thread wrapped around your Runnable (named "thread"). Then do

thread.start();
thread.join(10000);
if (thread.isAlive()) {
  thread.interrupt();
}

As NPE mentioned, unless you are coding myMethod() yourself or know that it is sensitive to interruptions, there is no guarantee that this will actually kill the thread.

If you are implementing myMethod yourself, then what you need to do is have something like this inside the loop that method runs within the myMethod():

if (Thread.interrupted()) {
  break;  // or whatever you need to do to end the method quickly
}

I've left out exception handling. Your compiler will tell you what you need to do in that respect.

BPS
  • 1,606
  • 20
  • 37
1

With two separated threads:

class Job implements Runnable {

        public void run(){
            try{
              myMethod();  // declared within this class or wherever you want
            } catch(InterruptedException){
                System.out.println("Interrupted now due probably to infinite loop !!");
            } 
        }

        public static void main(String[] args) throws InterruptedException {
           Job job = new Job();
           Thread process = new Thread(job);
           process.start(); 
           process.join(10000);  //wait here in order to detect wrong loop
           if(process.isAlive()){
             process.interrupt();
           }
        }
}
Mik378
  • 21,881
  • 15
  • 82
  • 180
  • I like this however myMethod() doesn't throw InterruptedException. I have no control over that method. Am I missing a detail? I'm almost there with this solution. Thanks. – Dale Dec 06 '12 at 21:24
  • @Dale Mmm, without a minimum of cooperation of the concerned thread, it's not possible to deal with any chosen interruption. You HAVE TO find a way to alter `myMethod()` by another way :( – Mik378 Dec 06 '12 at 23:47
  • Darn. I was afraid of that. And multi-threading is the only approach to solving this problem? – Dale Dec 07 '12 at 02:48
  • @Dale One solution would be to analyse exactly what `myMethod()` does and "copy" it in YOUR environment (even if it's bad but it is the unique way), so that you could add the famous `throws InterruptedException`. If this method actually deals with an EJB or another remote mechanism (or even I/O), why not redefines a relevant timeout in configuration files in order to avoid the feeling of infinite loop. – Mik378 Dec 07 '12 at 03:04
0

I agree with NPE, your best bet is to use multithreading with a separate process. That seems to be the safest way if you can't debug the method. Other options would be to simply use a timer and throw an exception if the timer exceeds 10 seconds. But that would be kind of unorthodox.

Linus Kleen
  • 33,871
  • 11
  • 91
  • 99
  • I like the idea of using a timer and throwing an exception. Why is it unorthodox and is unorthodox a bad thing (in this case)? – Dale Dec 06 '12 at 17:17