views:

4129

answers:

15

Here is my problem: I've got a dialog with some parameters that the user can change (via a spinner for example). Each time one of these parameters is changed, I launch a thread to update a 3D view according to the new parameter value. If the user changes another value (or the same value again by clicking many times on the spinner arrow) while the first thread is working, I would like to abort the first thread (and the update of the 3D view) and launch a new one with the latest parameter value.

How can I do something like that?

PS: There is no loop in the run() method of my thread, so checking for a flag is not an option: the thread updating the 3D view basically only calls a single method that is very long to execute. I can't add any flag in this method asking to abort either as I do not have access to its code.

+8  A: 

The thread that is updating the 3D view should periodically check some flag (use a volatile boolean) to see if it should terminate. When you want to abort the thread, just set the flag. When the thread next checks the flag, it should simply break out of whatever loop it is using to update the view and return from its run method.

If you truly cannot access the code the Thread is running to have it check a flag, then there is no safe way to stop the Thread. Does this Thread ever terminate normally before your application completes? If so, what causes it to stop?

If it runs for some long period of time, and you simply must end it, you can consider using the deprecated Thread.stop() method. However, it was deprecated for a good reason. If that Thread is stopped while in the middle of some operation that leaves something in an inconsistent state or some resource not cleaned up properly, then you could be in trouble. Here's a note from the documentation:

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. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait. For more information, see Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?

Dave L.
The tread updating the 3D view basically only calls a single method that is very long to execute. I can't add any flag in this method as I do not have access to its code. So this solution cannot be used here.
jumar
The solution proposed by Dave L. is correct. If you have no access to the source of the third party code then perhaps the only recourse you have left is bytecode manipulation. Using a library such as ASM (http://asm.objectweb.org/) you can modify a class at runtime and "inject" your own code.
Boris Terzic
A: 

Maybe this can help you: How can we kill the running thread in java?

u can kill the partictular thread by setting external class varaiable.

 Class Outer
 {    
    public static flag=true;
    Outer()
    {
        new Test().start();
    } 
    class Test extends Thread
    {               
       public void run()
       {
         while(Outer.flag)
         {
          //do ur work here
         }  
       }
    }
  }

if u want to stop the above thread , set flag variable as false. The another way to kill a thread is just register ur thread with ThreadGroup. and use the method destroy() of ThreadGroup. and this way is also used kill similar threads by creating them as group or register with group.

Olvagor
If you want people to take you seriously, stop using "u" and "ur". Take the time to type that whole extra 2 characters - it won't delay you that long.
Paul Tomblin
+1  A: 

The way I have implemented something like this in the past is to implement a shutdown() method in my Runnable subclass which sets an instance variable called should_shutdown to true. The run() method normally does something in a loop, and will periodically check should_shutdown and when it is true, returns, or calls do_shutdown() and then returns.

You should keep a reference to the current worker thread handy, and when the user changes a value, call shutdown() on the current thread, and wait for it to shutdown. Then you can launch a new thread.

I would not recommend using Thread.stop as it was deprecated last time I checked.

edit

Read your comment about how your worker thread just calls another method which takes a while to run, so the above does not apply. In this case, your only real options are to try calling interrupt() and see if has any effect. If not, consider somehow manually causing the function your worker thread is calling to break. For example, it sounds like it is doing some complex rendering, so maybe destroy the canvas and cause it to throw an exception. This is not a nice solution, but as far as I can tell, this is the only way to stop a thread in suituations like this.

Cheers,
Steve

freespace
A: 

A thread will exit once it's run() method is complete, so you need some check which will make it finish the method.

You can interrupt the thread, and then have some check which would periodically check isInterrupted() and return out of the run() method.

You could also use a boolean which gets periodically checked within the thread, and makes it return if so, or put the thread inside a loop if it's doing some repetative task and it will then exit the run() method when you set the boolean. For example,

static boolean shouldExit = false;
Thread t = new Thread(new Runnable() {
    public void run() {
        while (!shouldExit) {
            // do stuff
        }
    }
}).start();
Rich Adams
+1  A: 

Unfortunately killing a thread is inherently unsafe due to the possibilities of using resources that can be synchronized by locks and if the thread you kill currently has a lock could result in the program going into deadlock (constant attempt to grab a resource that cannot be obtained). You will have to manually check if it needs to be killed from the thread that you want to stop. Volatile will ensure checking the variable's true value rather than something that may have been stored previously. On a side note Thread.join on the exiting thread to ensure you wait until the dying thread is actually gone before you do anything rather than checking all the time.

bmeck
+2  A: 

Instead of rolling your own boolean flag, why no just use the thread interrupts mechanism already in Java threads? Depending on how the internals were implements in the code you can't change, you may be able to abort part of it's execution too.

Outer Thread:

if(oldThread.isRunning())
{
    oldThread.interrupt();
    // Be careful if you're doing this in response to a user
    // action on the Event Thread
    // Blocking the Event Dispatch Thread in Java is BAD BAD BAD
    oldThread.join();
}

oldThread = new Thread(someRunnable);
oldThread.start();

Inner Runnable/Thread:

public void run()
{
    // If this is all you're doing, interrupts and boolean flags may not work
    callExternalMethod(args);
}

public void run()
{
    while(!Thread.currentThread().isInterrupted)
    {
        // If you have multiple steps in here, check interrupted peridically and
        // abort the while loop cleanly
    }
}
basszero
To answer your question, it is because Thread.intrerrupt() can cause side effects by throwing exceptions during certain IO or concurrency operations. Sometimes this is exactly what you want, but not always.
Dave L.
A: 

Since you're dealing with code you don't have access to you're probably out of luck. The standard procedure (as outlined in the other answers) is to have a flag that is checked periodically by the running thread. If the flag is set, do cleanup and exit.

Since that option is not available to you, the only other option is to force quit the running process. This used to be possible by calling Thread.stop(), but that method has been permanently deprecated for the following reason (copied from the javadocs):

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.

More info on this topic can be found here.

One absolute sure way you could accomplish your request (although this is not a very efficient way to do this) is to start a new java process via Runtime.exec() and then stopping that process as necessary via Process.destroy(). Sharing state between processes like this is not exactly trivial, however.

toluju
A: 

Instead of playing with thread starting and stopping, have you considered having the thread observe the properties that you're changing through your interface? You will at some point still want a stop condition for your thread, but this can be done this was as well. If you're a fan of MVC, this fits nicely into that sort of design

Sorry, after re-reading your question, neither this nor any of the other 'check variable' suggestions will solve your problem.

Nerdfest
+1  A: 

Isn't this a little like asking "How can I abort a thread when no method other than Thread.stop() is available?"

Obviously, the only valid answer is Thread.stop(). Its ugly, could break things in some circumstances, can lead to memory/resource leaks, and is frowned upon by TLEJD (The League of Extraordinary Java Developers), however it can still be useful in a few cases like this. There really isn't any other method if the third party code doesn't have some close method available to it.

OTOH, sometimes there are backdoor close methods. Ie, closing an underlying stream that its working with, or some other resource that it needs to do its job. This is seldom better than just calling Thread.stop() and letting it experience a ThreadDeathException, however.

jsight
A: 

You appear to not have any control over the thread that is rendering the screen but you do appear to have control of the spinner component. I would disable the spinner while the thread is rendering the screen. This way the user at least has some feedback relating to their actions.

Javamann
+4  A: 

Try interrupt() as some have said to see if it makes any difference to your thread. If not, try destroying or closing a resource that will make the thread stop. That has a chance of being a little better than trying to throw Thread.stop() at it.

If performance is tolerable, you might view each 3D update as a discrete non-interruptible event and just let it run through to conclusion, checking afterward if there's a new latest update to perform. This might make the GUI a little choppy to users, as they would be able to make five changes, then see the graphical results from how things were five changes ago, then see the result of their latest change. But depending on how long this process is, it might be tolerable, and it would avoid having to kill the thread. Design might look like this:

boolean stopFlag = false;
Object[] latestArgs = null;

public void run() {
  while (!stopFlag) {
    if (latestArgs != null) {
      Object[] args = latestArgs;
      latestArgs = null;
      perform3dUpdate(args);
    } else {
      Thread.sleep(500);
    }
  }
}

public void endThread() {
  stopFlag = true;
}

public void updateSettings(Object[] args) {
  latestArgs = args;
}
skiphoppy
That will be my solution, thanks. Using a single looping thread instead of spawning new ones each time seems a good option. I made only a slight modification: I only call perform3dUpdate() if latestArgs have been modified since last pass
jumar
Glad I could help, jumar! This was my first stackoverflow post; I signed up specifically to post this idea. :)
skiphoppy
Two modifications I'd make to endThread: 1. If you have access to the thread object for the current class, then I would interrupt it to abort the sleep() call early. 2. Again, if you can find the thread, do a thread.join() at the end of endThread()
nsayer
This is not correct according to java spec. the flag should be volatile or accessed with synchronize.
Frederic Morin
You should be using a condition variable to manage the waiting on the settings being updated. Sleeping for 500 milliseconds could sleep for longer than that, but never shorter. Probably instead you wanted to sleep for no more than 500 milliseconds or until the settings are updated again.You can use intrinsic locks with Object#wait(long) and Object#notify(), but I favor using the explicit Lock and Condition types in the java.util.concurrent.locks package. Rewriting the example code is more than I can fit in a comment like this. If you need more help implementing these ideas, please say so.
seh
+1  A: 

I suggest that you just prevent multiple Threads by using wait and notify so that if the user changes the value many times it will only run the Thread once. If the users changes the value 10 times it will fire off the Thread at the first change and then any changes made before the Thread is done all get "rolled up" into one notification. That won't stop a Thread but there are no good ways to do that based on your description.

James A. N. Stauffer
A: 

The solutions that purpose the usage of a boolean field are the right direction. But the field must be volatile. The Java Language Spec says:

"For example, in the following (broken) code fragment, assume that this.done is a non- volatile boolean field:

while (!this.done)
  Thread.sleep(1000);

The compiler is free to read the field this.done just once, and reuse the cached value in each execution of the loop. This would mean that the loop would never terminate, even if another thread changed the value of this.done."

As far as I remember "Java Concurrency in Pratice" purposes to use the interrupt()) and interrupted()) methods of java.lang.Thread.

dmeister
A: 

The accepted answer to this question allows you to submit batch work into a background thread. This might be a better pattern for that:

public abstract class dispatcher<T> extends Thread {

  protected abstract void processItem(T work);

  private List<T> workItems = new ArrayList<T>();
  private boolean stopping = false;
  public void submit(T work) {
    synchronized(workItems) {
      workItems.add(work);
      workItems.notify();
    }
  }
  public void exit() {
    stopping = true;
    synchronized(workItems) {
      workItems.notifyAll();
    }
    this.join();
  }
  public void run() {
    while(!stopping) {
      T work;
      synchronized(workItems) {
        if (workItems.empty()) {
            workItems.wait();
            continue;
        }
        work = workItems.remove(0);
      }
      this.processItem(work);
    }
  }
}

To use this class, extend it, providing a type for T and an implementation of processItem(). Then just construct one and call start() on it.

You might consider adding an abortPending method:

public void abortPending() {
  synchronized(workItems) {
    workItems.clear();
  }
}

for those cases where the user has skipped ahead of the rendering engine and you want to throw away the work that has been scheduled so far.

nsayer
A: 

The correct answer is to not use a thread.

You should be using Executors, see the package: java.util.concurrent

Pyrolistical
I am sorry but saying that executors are better than threads without explaining why this is, it's not helpful. So I ask you this: in what ways are executors better than threads? Are they *always* better or are there times when threads are preferred?
Adam Asham