Saturday, February 22, 2014

Interrupting a Thread in Java

I have been working on a priority change request which was supposed to be fixed by end of business hour today. Today morning, I was totally engrossed into it when my boss interrupted me to convey that CR has been deferred. Gosh! what a relief it was. 

An interrupt is basically an indication to a thread that it should do something else instead of whatever it is doing right now. Something else is subjective here;  thread could abort or terminate the task, ignore the interrupt request after acknowledging it or it could even ignore it altogether as if nothing happened.
Usually interrupt mechanism works between two threads. One thread raises interrupt for other thread. Once interrupt is received by the other thread, it can act as per its wish. Thread can also interrupt itself.

Interrupting a Thread

Interrupting a thread is quite trivial. Just get a handle to thread and call interrupt method on it. Done!
              t.interrupt();

Below class demonstrates how to call interrupt on a thread. Main thread creates a new thread which keeps on incrementing and printing a counter.

 public class InterruptDemo1 {   
    static int counter = 0 ;   
    public static void main(String[] args) {   
       Runnable task = new Runnable(){   
         public void run(){   
            while(true){   
              System.out.println(" val :"+ counter++);                
            }   
         }   
       };   
       Thread secondThread = new Thread(task);   
       secondThread.start();     
       secondThread.interrupt();      
    }   
  }   

If you run above program, it will go on and on, printing the incremented value (couldn't see it stopping for 10 minutes on my machine).
In the last line, main thread interrupts secondThread. But it is not making any difference to the execution of the program. Is it all cool?

Handling Interrupt

As far as raising interrupt is concerned, above class demonstrates it perfectly. The problem is actually with second thread which is not handling the raised interrupt. And that's the reason why you see uninterrupted value on your console. So even if an interrupt is raised the thread can chose to ignore it.

In modified class below, interrupt gets handled by the task/thread.

 public class InterruptDemo2 {  
      static int counter = 0 ;  
      public static void main(String[] args) {  
           Runnable task = new Runnable(){  
                public void run(){  
                     while(true){  
                          System.out.println(" val :"+ counter++);  
                          if(Thread.interrupted())  //Thread refers to current thread
                               return;  
                     }  
                }  
           };  
           Thread secondThread = new Thread(task);  
           secondThread.start();  
           secondThread.interrupt();  
      }  
 }  

Now interrupt is getting handled in the second thread (run above program to confirm the same).


Details on Interrupt methods of Thread

 package java.lang;  
 public class Thread implements Runnable{  
      public void interrupt(){..}  
      public boolean isInterrupted(){..}  
      public static boolean interrupted(){..}  
   ...  
 }  

As discussed in previous examples, interrupt() method can be used to interrupt a thread. Thread maintains this state through a boolean interrupted status flag. This flag can be used to check the status of interruption by calling isInterrupted() method. And interrupted() method returns the status as well as clears the value. This is the only way to clear the interrupt status flag (i.e. sets it to false). Just be careful in the usage of this method though. Your task/thread might eat the interrupt. Best approach is, either handle interruption ( by exiting or throwing InterruptedException) or restore the interruption status by calling interrupt() again.

Blocking methods like Thread.sleep and Object.wait can also detect interrupt on a thread. These methods respond to interrupt by clearing the status flag and also by throwing InterruptedException.

Stopping a Thread

Stopping a task (and thread) safely and quickly is not easy. We need a cooperative mechanism to make sure that stopping the thread doesn't leave it in an inconsistent state. This was the reason why Java designers deprecated stop and suspend method from Thread class.

One of the most wildly used approach is, keep a thread-safe flag to notify to the thread that it can cancel the task. But this is not a reliable approach, task might not check the cancelled flag if it's making blocking API call.

          volatile boolean cancelled = false;    //class attribute

           //task component
            if(!cancelled){
                  //blocking api call
            }else{
               return;
            }

Interruption mechanism discussed in this post, is safest and most sensible approach to stop a thread. So you can design your task in such a way that when it receives interrupt, it can come out of task gracefully.

--happy interruption!

No comments:

Post a Comment