Java線程的傳說(1)——中斷線程Interrupted的用處

中斷線程 —— interrupt() 

 一個正在運行的線程除了正常的時間片中斷之外,能否被其他線程控制?或者說其他線程能否讓指定線程放棄CPU或者提前結束運行? 除了線程同步機制之外,還有兩種方法:
       (1) Thread.stop(), Thread.suspend(), Thread.resume() 和Runtime.runFinalizersOnExit() 這些終止線程運行的方法 。這些方法已經被廢棄,使用它們是極端不安全的。
       (2) Thread.interrupt() 方法是很好的選擇。但是使用的時候我們必須好好理解一下它的用處。

  1. //無法中斷正在運行的線程代碼     
  2. class TestRunnable implements Runnable{    
  3.       public void run(){    
  4.             while(true)    
  5.             {    
  6.                   System.out.println( "Thread is running..." );    
  7.                   long time = System.currentTimeMillis();//去系統時間的毫秒數     
  8.             while((System.currentTimeMillis()-time < 1000)) {    
  9.                    //程序循環1秒鐘,不同於sleep(1000)會阻塞進程。     
  10.             }    
  11.               }    
  12.        }    
  13. }    
  14. public class ThreadDemo{    
  15.          public static void main(String[] args){    
  16.                Runnable r=new TestRunnable();    
  17.                Thread th1=new Thread(r);    
  18.                th1.start();    
  19.                th1.interrupt();             
  20.         }    
  21. }    
  22. /運行結果:一秒鐘打印一次Thread is running...。程序沒有終止的任何跡象   
 //無法中斷正在運行的線程代碼  
 class TestRunnable implements Runnable{  
       public void run(){  
             while(true)  
             {  
                   System.out.println( "Thread is running..." );  
                   long time = System.currentTimeMillis();//去系統時間的毫秒數  
             while((System.currentTimeMillis()-time < 1000)) {  
                    //程序循環1秒鐘,不同於sleep(1000)會阻塞進程。  
             }  
               }  
        }  
 }  
 public class ThreadDemo{  
          public static void main(String[] args){  
                Runnable r=new TestRunnable();  
                Thread th1=new Thread(r);  
                th1.start();  
                th1.interrupt();           
         }  
 }  
//運行結果:一秒鐘打印一次Thread is running...。程序沒有終止的任何跡象 

上面的代碼說明interrupt()並沒有中斷一個正在運行的線程,或者說讓一個running中的線程放棄CPU。那麼interrupt到底中斷什麼。
       首先我們看看interrupt究竟在幹什麼。
       當我們調用th1.interrput()的時候,線程th1的中斷狀態(interrupted status) 會被置位。我們可以通過Thread.currentThread().isInterrupted() 來檢查這個布爾型的中斷狀態。
        在Core Java中有這樣一句話:"沒有任何語言方面的需求要求一個被中斷的程序應該終止。中斷一個線程只是爲了引起該線程的注意,被中斷線程可以決定如何應對中斷 "。好好體會這句話的含義,看看下面的代碼:

  1. //Interrupted的經典使用代碼     
  2. public void run(){    
  3.         try{    
  4.              ....    
  5.              while(!Thread.currentThread().isInterrupted()&& more work to do){    
  6.                     // do more work;     
  7.              }    
  8.         }catch(InterruptedException e){    
  9.                     // thread was interrupted during sleep or wait     
  10.         }    
  11.         finally{    
  12.                    // cleanup, if required     
  13.         }    
  14. }    
 //Interrupted的經典使用代碼  
 public void run(){  
         try{  
              ....  
              while(!Thread.currentThread().isInterrupted()&& more work to do){  
                     // do more work;  
              }  
         }catch(InterruptedException e){  
                     // thread was interrupted during sleep or wait  
         }  
         finally{  
                    // cleanup, if required  
         }  
 }  

很顯然,在上面代碼中,while循環有一個決定因素就是需要不停的檢查自己的中斷狀態。當外部線程調用該線程的interrupt 時,使得中斷狀態置位。這是該線程將終止循環,不在執行循環中的do more work了。

       這說明: interrupt中斷的是線程的某一部分業務邏輯,前提是線程需要檢查自己的中斷狀態(isInterrupted())。

       但是當th1被阻塞的時候,比如被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞時。調用它的interrput()方法。可想而知,沒有佔用CPU運行的線程是不可能給自己的中斷狀態置位的。這就會產生一個InterruptedException異常。

  1.  //中斷一個被阻塞的線程代碼   
  2. class TestRunnable implements Runnable{  
  3.      public void run(){  
  4.           try{  
  5.         Thread.sleep(1000000); //這個線程將被阻塞1000秒   
  6.        }catch(InterruptedException e){  
  7.          e.printStackTrace();  
  8.                      //do more work and return.   
  9.           }  
  10.      }  
  11. }  
  12. public class TestDemo2{  
  13.       public static void main(String[] args) {  
  14.             Runnable tr=new TestRunnable();  
  15.             Thread th1=new Thread(tr);  
  16.             th1.start(); //開始執行分線程   
  17.         while(true){  
  18.        th1.interrupt();  //中斷這個分線程   
  19.         }  
  20.       }  
  21. }  
  22. /*運行結果: 
  23.    java.lang.InterruptedException: sleep interrupted 
  24.         at java.lang.Thread.sleep(Native Method) 
  25.         at TestRunnable.run(TestDemo2.java:4) 
  26.         at java.lang.Thread.run(Unknown Source)*/  
 //中斷一個被阻塞的線程代碼
class TestRunnable implements Runnable{
     public void run(){
          try{
	    Thread.sleep(1000000); //這個線程將被阻塞1000秒
       }catch(InterruptedException e){
	     e.printStackTrace();
                     //do more work and return.
          }
     }
}
public class TestDemo2{
      public static void main(String[] args) {
            Runnable tr=new TestRunnable();
            Thread th1=new Thread(tr);
            th1.start(); //開始執行分線程
        while(true){
	   th1.interrupt();  //中斷這個分線程
        }
      }
}
/*運行結果:
   java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at TestRunnable.run(TestDemo2.java:4)
        at java.lang.Thread.run(Unknown Source)*/

* 如果線程被阻塞,它便不能覈查共享變量,也就不能停止。這在許多情況下會發生,例如調用
* Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,他們都可能永
* 久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使
* 用某種機制使得線程更早地退出被阻塞的狀態。很不幸運,不存在這樣一種機制對所有的情況
* 都適用,但是,根據情況不同卻可以使用特定的技術。使用Thread.interrupt()中斷線程正
* 如Example1中所描述的,Thread.interrupt()方法不會中斷一個正在運行的線程。這一方法
* 實際上完成的是,在線程受到阻塞時拋出一箇中斷信號,這樣線程就得以退出阻塞的狀態。更
* 確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麼,
* 它將接收到一箇中斷異常(InterruptedException),從而提早地終結被阻塞狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章