程式設計人員在程式設計過程中,多執行緒呈現出了一組新的難題,而如何中斷一個正在運行的執行緒則是難題之一。本文中,作者將講述相關的方法。
程序是很簡易的。然而,在程式設計師面前,多執行緒呈現出了一組新的難題,如果沒有被恰當的解決,將導致意外的行為以及細微的、難以發現的錯誤。
在本篇文章中,我們針對這些難題之一:如何中斷一個正在運行的執行緒。
背景中斷(Interrupt)一個執行緒意味著在該執行緒完成任務之前停止其正在進行的一切,有效地中止其當前的操作。執行緒是死亡、還是等待新的任務或是繼續運行至下一步,就取決於這個程式。雖然初次看來它可能顯得簡單,但是,你必須進行一些預警以實現期望的結果。你最好還是牢記以下的幾點告誡。
首先,忘記Thread.stop方法。雖然它確實停止了一個正在運行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來的JAVA版本中,它將不復存在。
一些輕率的傢伙可能被另一種方法Thread.interrupt所迷惑。儘管,其名稱似乎在暗示著什麼,然而,這種方法並不會中斷一個正在運行的線程(待會將進一步說明),正如Listing A中所描述的那樣。它創建了一個線程,並且試圖使用Thread.interrupt方法停止該線程。 Thread.sleep()方法的調用,為執行緒的初始化和中止提供了充裕的時間。線程本身並不參與任何有用的操作。
class Example1 extends Thread { boolean stop=false; 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..." ); //System.exit(0); } public void run() { while(!stop){ System.out.println( "Thread is running..." ); long time = System.currentTimeMillis(); while((System.currentTimeMillis()-time < 1000)) { } } System.out.println("Thread exiting under request..." ); } }
如果你運行了Listing A中的程式碼,你將在控制台看到以下輸出:
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... .....................
甚至,在Thread.interrupt()被呼叫後,執行緒仍然繼續運行。
真正地中斷一個執行緒
中斷執行緒最好的,最受推薦的方式是,使用共享變數(shared variable)發出訊號,告訴執行緒必須停止正在執行的任務。執行緒必須週期性的核查此變數(尤其在冗餘操作期間),然後有秩序地中止任務。 Listing B描述了這個方式。
Listing B class Example2 extends Thread { volatile boolean stop = 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.stop = true; Thread.sleep( 3000 ); System.out.println( "Stopping application..." ); //System.exit( 0 ); } public void run() { while ( !stop ) { System.out.println( "Thread is running..." ); long time = System.currentTimeMillis(); while ( (System.currentTimeMillis()-time < 1000) && (!stop) ) { } } System.out.println( "Thread exiting under request..." ); } }
運行Listing B中的程式碼將產生如下輸出(注意線程是如何有秩序的退出的)
Starting thread... Thread is running... Thread is running... Thread is running... Asking thread to stop... Thread exiting under request... Stopping application...
雖然該方法要求一些編碼,但並不難實現。同時,它給予線程機會進行必要的清理工作,這在任何一個多線程應用程式中都是絕對需要的。請確認將共享變數定義成volatile 類型或將對它的一切存取封入同步的區塊/方法(synchronized blocks/methods)中。
到目前為止一切順利!但是,當執行緒等待某些事件發生而被阻塞,又會發生什麼事?當然,如果線程被阻塞,它便不能核查共享變量,也就不能停止。這在許多情況下會發生,例如當呼叫Object.wait()、ServerSocket.accept()和DatagramSocket.receive()時,這裡僅舉出一些。
他們都可能永久的阻塞線程。即使發生超時,在超時期滿之前持續等待也是不可行和不適當的,所以,要使用某種機制使得線程更早地退出被阻塞的狀態。
很不幸運,不存在這樣一種機制對所有的情況都適用,但是,根據情況不同卻可以使用特定的技術。在下面的環節,我將解答一下最普遍的例子。
以上就是Java怎樣中斷一個運作中的執行緒(1)的內容,更多相關內容請關注PHP中文網(www.php.cn)!