views:

531

answers:

7

Possible Duplicate: How do you kill a thread in Java?


I need to stop doing some big task by sending the interruption signal to the Thread. I am using most of the APIs from java.util.concurrent.*. My task is send to the Thread and is executed. This task comes from the client so I do not have any control over that code.

Task are something similar to:

public class Task1 extends Thread {
 public void run() {
  while(true){
   if(Thread.interrupted()){
    return;
   }
   for(int i=0; i<Integer.MAX_VALUE; i++){
    System.out.println("I am task 1 " + i);
   }

  }
 }
};

I want to basically stop looping through the for-loop when it receives the interruption signal (Please note that I cannot put the Thread.interrputed() logic inside for-loop as it comes from the client.) I have another class that use the Executor to execute this task.

public class ConcurrentTest {

public static void main(String[] args) {
 // TODO Auto-generated method stub

 ConcurrentTest test = new ConcurrentTest();
 ExecutorService executorService = Executors.newFixedThreadPool(2);

 Task1 task1 = new Task1();
 Future<?> runningTask1 = executorService.submit(task1);

 Task2 task2 = new Task2();
 Future<?> runningTask2 = executorService.submit(task2);

 //Stop First task after 5 second
 try {
  TimeUnit.SECONDS.sleep(5);
 } catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 runningTask1.cancel(Boolean.TRUE);
 System.out.println("runningTask1.isDone is " + runningTask1.isDone());
 System.out.println("runningTask1.isCancelled is " + runningTask1.isCancelled());
 //Stop Second task after 10 second
 try{
  TimeUnit.SECONDS.sleep(3);
 }catch(InterruptedException e){
  e.printStackTrace();
 }
 runningTask2.cancel(Boolean.TRUE);
 System.out.println("runningTask2.isDone is " + runningTask2.isDone());
 System.out.println("runningTask2.isCancelled is " + runningTask2.isCancelled());
}

}

Task2 is :

public class Task2 extends Thread{
 public void run() {
  while(true){
   if(Thread.interrupted()){
    return;
   }
   System.out.println("I am task 2");
  }
 }
};

Task2 is interrpted however Task1 is never interrupted and continue executing inside for loop. I cannot put any logic inside client code (something similar to for-loop). I need help from SO community to resolve this issue. Thanks.

A: 

Check for interrupt twice inside the while loop and in the for loop.

            while(true){
                    if(Thread.interrupted()){
                            return;
                    }
                    for(int i=0; i<Integer.MAX_VALUE; i++){
                         if(Thread.interrupted()){
                              return;
                         }

                         System.out.println("I am task 1 " + i);
                    }

            }
Sergey
"Please note that I cannot put the Thread.interrputed() logic inside for-loop as it comes from the client."
erickson
Yes, I don't have control over the task (like for-loop here) as it comes from the client.
royalGhost
What you could do is create another thread which would periodically check the state of your running threads, and invoke the stop() (err... it's deprecated but still works) method on the thread to force it to terminate when so necessary. However, this is very unsafe and ugly. If your thread is using shared resource and becomes terminated you may have a deadlock in your application as nobody else would be able to access that shared resource since the thread terminated without cleanup. Unfortunately, i don't see an elegant solution to this.
Sergey
Actually, i may have to take the deadlock issue back. According to this http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Thread.html stop() will unlock all monitors, so now you may be potentially dealing with your shared resource being released in inconsistent or damaged state.
Sergey
A: 

If someone else is providing the code in the worker thread (as a jar?) do they call your code at all as part of their work? You could put the check for interrupted in functions you write that they call and throw an unchecked exception that we hope will terminate the thread.

// Called from the worker thread code that someone else writes,
// hopefully often so that we notice when we're interrupted.
public void doSomething() {
  if (Thread.interrupted()) {
    throw new MyRuntimeException();
  }
  // do what this method is meant to do ...
}

Be careful to warn the developers writing that code: see this article describing some of the problems that can arise.

So, in short, if you're not writing that code, it's best to try to get whoever is to check for Thread.interrupted() so that they can exit cleanly.

Harold L
A: 

Interruption is really a cooperative cancellation mechanism, not a preemptive one. It takes the cooperation from the task to do a graceful cancellation. If the task is uninterruptible (i.e. does not abort its action by checking the interrupt status or responding to the InterruptedException), there is not much you can do to cancel the task. Delivering the interrupt is trivial; it's really how the task responds to it.

One possible solution might be to inject your code into the task via things like dynamic instrumentation. However, even that is not a sure bet, and it would require injecting your code inside the while loop if the task uses a while loop.

sjlee
+1  A: 

I would provide a mechanism that allows client code to handle the stopping signal cooperatively. If the client code handles signal, then your app and the client agree that it can do stopped in timely manner. Otherwise, you interrupt the thread when the code gets back to your interrupted() checking. My point is that you should ask the client code to be cooperative instead of interrupting it blindly.

weilin8
+3  A: 

The only bomb-proof solution is to run the client supplied code in an Isolate. An isolate is essentially a private virtual machine that a Java app can create, managed and communicate with. In particular, the parent app can safely kill an isolate and all its threads.

Reference: JSR-000121 Application Isolation API Specification - Final Release

The problem is finding a JVM that supports Isolates.

Stephen C
A: 

A simple approach to stopping threads is to define some stop flag for each thread and then periodically check that flag.

For example:

class MyTask implements Runnable {
    private AtomicBoolean stopflag = new AtomicBoolean();
    public void stop() {
        stopflag.set(true);
    }

    public void run() {
        while(true) {
            if(!stopflag.get()) 
                /// do some work
            else
                return;   // get out
        }
    }
}
Gregory Mostizky
+2  A: 

Re-read your questions and realized you don't have any control over the tasks code.

The reason why task1 doesn't interrupt is that interrupt() method doesn't actually interrupt anything, it will only cause the thread to interrupt if that thread is waiting on some lock or sleeping, otherwise it doesn't actually do anything except setting the status.

The only way to kill task1 for you is to use Thread.stop() method. Be careful though is it can be very dangerous and make your system unstable. See more here.

Gregory Mostizky