2009年4月21日 星期二

搭配interrupt()終止thread

Thread.interrupt()的迷思

切記勿使用Thread.stop()。雖然它確實停止了一個正在執行的thread,然而,這種方法是不安全也是
Deprecated.的,這意味在未來的JAVA版本中,它將不復存在。

至於
Thread.interrupt(),並不會中斷一個正在執行的thread,如以下程式碼:

class Example1 extends Thread {

    public static void main( String args[] ) throws Exception {
Example1 thread = new Example1();
System.out.println( "Starting thread..." );
thread.start();
Thread.sleep( 3000 );
System.out.println( "Interrupting thread..." );
thread.interrupt();
Thread.sleep( 3000 );
System.out.println("Stopping application..." );
}

public void run() {
while(!stop){
System.out.println( "Thread is running..." );
long time = System.currentTimeMillis();

while((System.currentTimeMillis()-time <>
}
}

System.out.println("Thread exiting under request..." );
}
}
其輸出結果為:

Starting thread...
Thread is running...
Thread is running...
Thread is running...
Interrupting thread...
Thread is running...
Thread is running...
Thread is running...
Stopping application...
Thread is running...
Thread is running...
Thread is running...

甚至,在call Thread.interrupt()後,Thread仍會繼續執行。


真正地中斷一個Thread


中斷thread最好的方式是,使用shared variable,以通知thread必須停止正在執行的任務。thread必須週期性的核查這一variable(尤其在冗餘操作期間),然後有秩序地中止任務,如以下所示:

class Example2 extends Thread {
volatile boolean terminate = false;

public static void main( String args[] ) throws Exception {
Example2 thread = new Example2();
System.out.println( "Starting thread..." );
thread.start();
Thread.sleep( 3000 );
System.out.println( "Asking thread to stop..." );
thread.terminate = true;
//thread.interrupt();
Thread.sleep( 3000 );
System.out.println( "Stopping application..." );
}

public void run() {
while ( !terminate ) {
System.out.println( "Thread is running..." );
long time = System.currentTimeMillis();

while ( (System.currentTimeMillis()-time <>
}
}

System.out.println( "Thread exiting under request..." );
}
}

此方式基本上可行,然,當tread因某些原因(如,Object.wait()、hread.sleep()、ServerSocket.accept()和DatagramSocket.receive()等)被block或處於waiting queue中,該thread便不能check shared variable(i.e. 上面程式碼中的terminate變數),自然就無法停止。所以,要使用某種機制使得線程更早地退出被阻塞的狀態。

很不幸運,不存在這樣一種機制對所有的情況都適用,但是,根據情況不同卻可以使用特定的技術。


使用Thread.interrupt()中斷thread


如以上所述,Thread.interrupt()並不會中斷一個thread。實際上,此方法作用是,在thread block時拋出一個中斷signal,這樣thread就得以退出block的狀態。更確切的說,如果thread被Object.wait, Thread.join和Thread.sleep三 種方法之一阻塞,那麼,它將接收到一個中斷異常(InterruptedException),從而提早地終結被block狀態。

因此,如果thread被上述幾種方法block,正確停止thread方式是設置shared variable,並搭配interrupt(),i.e., 將第2段程式碼中的comment (i.e., //thread.interrupt() )解開即可。如果thread沒有被block,這時使用interrupt()將不起任何作。在任何一種情況中,最後thread都將check shared variable然後再停止。

以下為javadoc原文:

interrupt

public void interrupt()
Interrupts this thread.

First the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.


Throws:
SecurityException - if the current thread cannot modify this thread

沒有留言:

張貼留言