views:

227

answers:

3

I am using a third-party library to process a large number of data sets. The process very occasionally goes into an infinite loop (or is blocked - don't know why and can't get into the code). I'd like to kill this after a set time and continue to the next case. A simple example is:

for (Object data : dataList) {
    Object result = TheirLibrary.processData(data);
    store(result);
}

processData normally takes 1 second max. I'd like to set a timer which kills processData() after , say, 10 seconds

EDIT I would appreciate a code snippet (I am not practiced in using Threads). The Executor approach looks useful but I don't quite know how to start. Also the pseudocode for the more conventional approach is too general for me to code.

@Steven Schlansker - suggests that unless the thirdparty app anticipates the interrupt it won't work. Again detail and examples would be appreciated

EDIT I got the precise solution I was wanting from my colleagues Sam Adams, which I am appending as an answer. It has more detail than the other answers, but I will give them both a vote. I'll mark Sam's as the approved answer

+5  A: 

Put the call to the library in another thread and kill this thread after a timeout. That way you could also proces multiple objects at the same time if they are not dependant to each other.


EDIT: Democode request

This is pseudo code so you have to improve and extend it. Also error checking weather a call was succesful or not will be of help.

for (Object data : dataList) {
    Thread t = new LibThread(data);
    // store the thread somewhere with an id
    // tid and starting time tstart 
    // threads
    t.start();
    }

while(!all threads finished)
{
    for (Thread t : threads)
    {
        // get start time of thread
        // and check the timeout
        if (runtime > timeout)
        {
            t.stop();
        }
    }
}

class LibThread extends Thread {
    Object data;

    public TextThread(Object data) 
    {
        this.data = data;
    }

    public void processData() 
    {
        Object result = TheirLibrary.processData(data);
        store(result);
    }
}
schoetbi
You beat me - i've deleted my similar answer, but i think it's worth mentioning that by using join(timeout) you'll wait just long enough...
Rob Fonseca-Ensor
+1 for being fair. Bandwidth is everything:-)
schoetbi
I would appreciate a short code example (PeterMR)
peter.murray.rust
+7  A: 

One of the ExecutorService.invokeAll(...) methods takes a timeout argument. Create a single Callable that calls the library, and wrap it in a List as an argument to that method. The Future returned indicate how it went.

(Note: untested by me)

Thorbjørn Ravn Andersen
Given this a +1 as this was the method I was going to write about. Could probably do with some code to explain how it all works. But definitely using java.util.concurrent is the way to do it.
Noel M
Feel free to write a better answer.
Thorbjørn Ravn Andersen
If the library doesn't sanely handle interrupts, you'll likely still never return from the infinite loop. :-(
Steven Schlansker
@Steven Schlansker the only secure way to handle this is to start a separate jvm and call the method with RMI. This way you can just kill the other jvm.
josefx
@Steven - an argument that every Java programmer should learn to safely handle interrupts.
justkt
@justkt - I'd love it if that were true, but the fact is that many do not!
Steven Schlansker
+1  A: 

Sam Adams sent me the following answer, which is my accepted one

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.interrupt();
}

and myRunnableCode regularly checks Thread.isInterrupted(), and exits cleanly if this returns true.

Alternatively you can do:

Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
  thread.stop();
}

But this method has been deprecated since it is DANGEROUS.

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#stop() "This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior."

I've implemented the second and it does what I want at present.

peter.murray.rust
@peter.murray.rust The second solution (which you say you've implemented) is the same as the solution and comment added to schoetbi's answer.
Jim Downing
@Jim Downing schoetbi's reply was pseudocode and didn't give the precise calls (e.g. "while(!all threads finished)" does not give the actual methods
peter.murray.rust