閱讀267 返回首頁    go 技術社區[雲棲]


對Thread.interrupt()方法很詳細的介紹

在JDK1.0中,可以用stop方法來終止,但是現在這種方法已經被禁用了,改用interrupt方法。


Thread.interrupt()方法不會中斷一個正在運行的線程。它的作用是,在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態。更確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那麼,它將接收到一個中斷異常(InterruptedException),從而提早地終結被阻塞狀態。


interrupt方法並不是強製終止線程,它隻能設置線程的interrupted狀態,而在線程中一般使用一下方式: 
while (!Thread.currentThread().isInterrupted() && more work to do)


{...}


而被block的線程(sleep() or join())在被調用interrupt時會產生InterruptException,此時是否終止線程由本線程自己決定。程序的一般形式是: 
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 

// exiting the run method terminates the thread 

Thread.sleep方法也會產生InterruptedException,因此,如果每次在做完一些工作後調用了sleep方法,那麼就不用檢查isInterrupted,而是直接捕捉InterruptedException。


---------------------------------------------------------------------------------------


假如我們有一個任務如下,交給一個Java線程來執行,如何才能保證調用interrupt()來中斷它呢?


class ATask implements Runnable{   
    private double d = 0.0;   
    public void run() {   
        //死循環執行打印"I am running!" 和做消耗時間的浮點計算   
        while (true) {   
            System.out.println("I am running!");   
            for (int i = 0; i < 900000; i++) {   
                d =  d + (Math.PI + Math.E) / d;   
            }   
            //給線程調度器可以切換到其它進程的信號   
            Thread.yield();   
        }   
    }   
}   
public class InterruptTaskTest {   
    public static void main(String[] args) throws Exception{   
        //將任務交給一個線程執行   
        Thread t = new Thread(new ATask());   
        t.start();   
        //運行一斷時間中斷線程   
        Thread.sleep(100);   
        System.out.println("****************************");   
        System.out.println("Interrupted Thread!");   
        System.out.println("****************************");   
        t.interrupt();   
    }   
}    
運行這個程序,我們發現調用interrupt()後,程序仍在運行,如果不強製結束,程序將一直運行下去,如下所示: 
......   
I am running!   
I am running!   
I am running!   
I am running!   
****************************   
Interrupted Thread!   
****************************   
I am running!   
I am running!   
I am running!   
I am running!   
I am running!   
....   
雖然中斷發生了,但線程仍然在進行,離開線程有兩種常用的方法:  
拋出InterruptedException和用Thread.interrupted()檢查是否發生中斷,下麵分別看一下這兩種方法:  
1.在阻塞操作時如Thread.sleep()時被中斷會拋出InterruptedException(注意,進行不能中斷的IO操作而阻塞和要獲得對象的鎖調用對象的synchronized方法而阻塞時不會拋出InterruptedException)  
Java代碼  
class ATask implements Runnable{   
    private double d = 0.0;   
    public void run() {   
        //死循環執行打印"I am running!" 和做消耗時間的浮點計算   
        try {   
            while (true) {   
                System.out.println("I am running!");   
                for (int i = 0; i < 900000; i++) {   
                    d =  d + (Math.PI + Math.E) / d;   
                }   
                //休眠一斷時間,中斷時會拋出InterruptedException   
                Thread.sleep(50);   
            }   
        } catch (InterruptedException e) {   
            System.out.println("ATask.run() interrupted!");   
        }   
    }   
}   
程序運行結果如下:  
Java代碼  
I am running!   
I am running!   
****************************   
Interrupted Thread!   
****************************   
ATask.run() interrupted!   
可以看到中斷任務時讓任務拋出InterruptedException來離開任務.  
2.Thread.interrupted()檢查是否發生中斷.Thread.interrupted()能告訴你線程是否發生中斷,並將清除中斷狀態標記,所以程序不會兩次通知你線程發生了中斷.  
Java代碼  
class ATask implements Runnable{   
    private double d = 0.0;   
    public void run() {   
        //檢查程序是否發生中斷   
        while (!Thread.interrupted()) {   
            System.out.println("I am running!");   
            for (int i = 0; i < 900000; i++) {   
                d = d + (Math.PI + Math.E) / d;   
            }   
        }   
        System.out.println("ATask.run() interrupted!");   
    }   
}   
程序運行結果如下:  
Java代碼  
I am running!   
I am running!   
I am running!   
I am running!   
I am running!   
I am running!   
I am running!   
****************************   
Interrupted Thread!   
****************************   
ATask.run() interrupted!   
我們可結合使用兩種方法來達到可以通過interrupt()中斷線程.請看下麵例子:  
Java代碼  
class ATask implements Runnable{   
    private double d = 0.0;   
    public void run() {   
        try {   
        //檢查程序是否發生中斷   
        while (!Thread.interrupted()) {   
            System.out.println("I am running!");   
            //point1 before sleep   
            Thread.sleep(20);   
            //point2 after sleep   
            System.out.println("Calculating");   
            for (int i = 0; i < 900000; i++) {   
                d = d + (Math.PI + Math.E) / d;   
            }   
        }   
        } catch (InterruptedException e) {   
            System.out.println("Exiting by Exception");   
        }   
        System.out.println("ATask.run() interrupted!");   
    }   
}   
在point1之前處point2之後發生中斷會產生兩種不同的結果,可以通過修改InterruptTaskTest main()裏的Thread.sleep()的時間來達到在point1之前產生中斷或在point2之後產生中斷.  
如果在point1之前發生中斷,程序會在調用Thread.sleep()時拋出InterruptedException從而結束線程.這和在Thread.sleep()時被中斷是一樣的效果.程序運行結果可能如下: 
Java代碼  
I am running!   
Calculating   
I am running!   
Calculating   
I am running!   
Calculating   
I am running!   
****************************   
Interrupted Thread!   
****************************   
Exiting by Exception   
ATask.run() interrupted!   
如果在point2之後發生中斷,線程會繼續執行到下一次while判斷中斷狀態時.程序運行結果可能如下:  
Java代碼  
I am running!   
Calculating   
I am running!   
Calculating   
I am running!   
Calculating   
****************************   
Interrupted Thread!   
****************************   
ATask.run() interrupted! 

最後更新:2017-04-03 22:15:39

  上一篇:go Thread.interrupt() 使用不當,導致程序無法退出
  下一篇:go Java Thread.interrupt 害人! 中斷JAVA線程