0

I have a function in Java. It normally returns a value after it completes its task. However, in some conditions it returns nothing. I create a runnable and run this function as a thread. However, because of its not returning a value, it does not finish although it does its task. The process stays alive because it waits a returning value. Is there a way to kill this thread after it is triggered or after a timeout? Stop() or Destroy() did not work. During debug, the thread is seen as alive and I want it to bi deleted/removed

Runnable runnable = new Runnable() {
            @Override
            public void run() {
               int stat = RunMyFunction();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
JoshuaJeanThree
  • 1,382
  • 2
  • 22
  • 41
  • 1
    Please, shoe the content of RunMyFunction, cause it's not clear what problem actually is? As a hint I'd suggest Interrupt mechanism to stop threads. – krems Aug 18 '14 at 11:05
  • 1
    *in some conditions it returns nothing* unless you mean the method execution is aborted through an exception, I hardly can believe that. – A4L Aug 18 '14 at 11:07
  • Yes, it is hard to believe but I am using a wsdl library function of a hardware and it works like that unfortunately. – JoshuaJeanThree Aug 18 '14 at 11:08
  • Consider using ExecuterService to timeout a thread. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html – naveejr Aug 18 '14 at 11:10

4 Answers4

1

Java does not support killing a thread via any method on java.lang.Thread.

stop() and destroy() do look promising at first glance, but they have both been deprecated.

The documentation for destroy states:

This method was originally designed to destroy this thread without any cleanup. However, the method was never implemented. If if were to be implemented, it would be deadlock-prone

and 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.

Thus when the documentation says 'deprecated', what it really means is that they are broken and must never be used!?! The Java API designers put a lot of work into backwards compatibility of their APIs, where other languages would have removed these methods Sun decided to keep them as their internal guides (rightly or wrongly) do not permit the removal of a public api method.

So, the question remains. How is one to get a thread to exit from another thread? Sadly one must go out of ones way to poll an exit variable. This can be a custom variable, or it can be a standard flag within java.lang.Thread that is accessible via 'interrupted()'. The advantage of using interrupted() is that other Java APIs such as IO support this flag during otherwise blocking API calls and will exit throwing an InterruptedException. The detection of calling interrupt() is not immediate, as it sets a flag and relies on the Thread to poll the variable at some point in the future.

Oracle offers a tutorial on how to code using interrupt here.

Chris K
  • 11,622
  • 1
  • 36
  • 49
1

The real problem you have is that RunMyFunction sometimes never terminates. As others have already stated, killing a thread is not intended in Java, so there is no good way to do it. Instead, you should reason about why you call a possibly non-terminating method. This looks like a code smell. Do the following:

If you are the author of RunMyFunction, make sure that it always terminates or it can be interrupted. You can do this by checking Thread.currentThread().isInterrupted() and throwing an InterruptedException when it is. E.g:

void run(){

    while(...){ // this loop sometimes runs forever
       if(Thread.currentThread().isInterrupted())
           throw new InterruptedException(); // Now, we can "kill" this thread here
    } 

}
gexicide
  • 38,535
  • 21
  • 92
  • 152
0

Using ExecuterService you can specify a timeout.

ExecutorService executor = Executors.newFixedThreadPool(1);
    List<Callable<String>> tasks = new ArrayList<Callable<String>>();

    tasks.add(new Callable<String>() {

        @Override
        public String call() throws Exception {
             int stat = RunMyFunction();
             return "Execution Finished";
        }
    });

    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                executor.invokeAll(tasks, 10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }).start();

invokeAll(...) is a blocking call so i've added inside a new thread.

naveejr
  • 735
  • 1
  • 15
  • 31
  • 1
    ExecutorService doesn't have any magic for killing threads. The task will keep running. – aioobe Aug 18 '14 at 11:24
  • I've edited the code. Actually when I test the code with Infinite loop inside the call() method with some System.out, the System output stopped after 10 seconds. doesn't it mean that task finished execution? – naveejr Aug 18 '14 at 11:33
  • 1
    I bet the thread pool thread is a daemon thread, so it won't prevent the JVM from terminating. – aioobe Aug 18 '14 at 11:34
  • @aioobe I think you are right, I'll delete this answer after some research on this topic. – naveejr Aug 18 '14 at 11:38
0

Solution 1: Timed run: If you want a method to return or throw an exception after a specified amount of time, use the following method to execute the method on a background thread while waiting for it to complete:

public static void timedRun(Runnable r, long timeout, TimeUnit unit)
    throws InterruptedException, TimeoutException {

    Future<?> task = executor.submit(r);
    try {
        task.get(timeout, unit);
    } catch (ExecutionException e) {
        throw launderThrowable(e.getCause());
    } finally {
        task.cancel(true);
    }
}

private static RuntimeException launderThrowable(Throwable t) {
    if (t instanceof RuntimeException) return (RuntimeException)t;
    else if (t instanceof Error) throw (Error)t;
    else throw new IllegalStateException("Not unchecked", t);
}

(Source: Goetz, Brian, Bloch, Joshua, Bowbeer, Joseph, Lea, Doug, Holmes, David and Peierls, Tim. Java Concurrency in Practice. : Addison-Wesley Longman, Amsterdam, 2006. Listing 5.13 and 7.10)

For executor, you can either create a new one using Executor.newSingleThreadExecutor(), or reuse an existing one.

But be warned: Although this method is guaranteed to return or throw an exception after the specified timeout, it cannot guarantee that the runnable will really stop! It interrupts the executing thread, but if the runnable does not react to thread interruption (e.g. by internally checking Thread.interrupted()), it may continue to run in the background - possibly forever - occupying a thread! But at least it does not block.

Solution 2: Timed run with custom threads: If there is any possibility beside thread interruption to cancel your method call, you can still use the approach above, but then you have to use an Executor with custom ThreadFactory that creates a special Thread instance with overridden interrupt method:

Executor executor = Executor.newSingleThreadExecutor(r -> new WsdlThread(r));

public class WsdlThread extends Thread {
    public WsdlThread(Runnable r) { super(r); }

    public void interrupt() {
        try {
            // TODO: do something that will interrupt the wsdl call
            // e.g. close connection to server, etc.
            // example: ((WsdlRunnable)r).getWsdlConnection().close();
        } finally {
            super.interrupt();
        }
    }
}

If this isn't possible too, and Thread.stop() doesn't work either, this last solution might work:

Solution 3: Start non-cancellable call in another JVM:

Use Runtime.exec to start another JVM and execute the method call there (See Executing a Java application in a separate process for more info on how to do this). Runtime.exec will return a Process object, which represents the running process.

You can kill it by calling destroy() or destroyForcibly().

Community
  • 1
  • 1
isnot2bad
  • 24,105
  • 2
  • 29
  • 50