Tutorial :How to interrupt the Thread when it is inside some loop doing long task?



Question:

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.


Solution:1

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.


Solution:2

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.


Solution:3

You can use a "stop" flag and a wrapper class to kill both your own tasks and the ones the client gives you.

public class MyTask implements Runnable {     private TaskController taskControl;       @Override     public void run() {       if(taskControl.abort()) {         return;       }       // Task logic ...     }  }    // Construct on main thread, call "run()" on a dedicated background thread.  public class TaskController implements Runnable {     private AtomicBoolean terminate = new AtomicBoolean(false);     private ThreadPoolExecutor yourTaskThreadPool;     private ThreadPoolExecutor otherTaskThreadPool;       @Override     public void run() {       // Your task construction, dispatch logic. Use your own thread pool         // Run the tasks you don't control in THEIR own pool       if(terminate.get()) {         otherTaskThreadPool.shutdown();       }       otherTaskThreadPool.execute( clientsTask ); // e.g. "task1"     }       public void AbortAllTasks() {         terminate.set(true);     }       public boolean abort() {         return terminate.get();     }  }   

Your tasks can take the controller ("this" pointer) as a construction parameter, and check the terminate flag in their run(). This allows you to asynchronously kill all of them by just calling TaskController.AbortAllTasks(). For the tasks you don't control, you can put your own interrupt logic in TaskController.run().


Solution:4

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.


Solution:5

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.


Solution:6

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);                      }                }  


Solution:7

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.


Solution:8

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          }      }  }  


Solution:9

You can NOT make it without putting changes in the for statement itself. as Sun depracated the methods for immediate Thread suspension. and they had their reasons. (see here) the only way to do that is to use a boolean inside the loop, or, if the Thread sleeps\wait inside the for loop, you can catch InterruptedException that is thrown by Thread.interuppt()


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »