對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!