題外話 複習多線程的知識,偶然看到一道題:如何正確的停止一個線程?我第一反應是使用stop()方法停止,操作以後發現stop已經被廢棄了。 經過查找資料,發現是使用interrupt()進行中斷標記然後在進行停止,特此寫這篇隨筆記錄一下。 stop()、suspend()的缺點 1.會導致一些清理工 ...
================================題外話=================================
複習多線程的知識,偶然看到一道題:如何正確的停止一個線程?我第一反應是使用stop()方法停止,操作以後發現stop已經被廢棄了。
經過查找資料,發現是使用interrupt()進行中斷標記然後在進行停止,特此寫這篇隨筆記錄一下。
------------------------------------------------------------------------------------------------------------------------------------
stop()、suspend()的缺點
1.會導致一些清理工作沒有進行,導致一些資源沒有得到回收,導致記憶體泄漏;
2.stop()停止線程會導致對鎖定的對象進行解鎖,在多線程情況下導致數據不一致問題。
interrupt()方法
interrupt()方法為為調用該方法的線程對象設置一個中斷標誌,註意!這裡是設置一個中斷標誌,絲毫不耽誤線程沒羞沒臊的運行。請看例子
1 public class App { 2 public static void main(String[] args) { 3 4 try { 5 MyThread thread = new MyThread(); 6 thread.start(); 7 thread.interrupt(); 8 System.out.println("執行了interrupt方法"); 9 } catch (Exception e) { 10 e.printStackTrace(); 11 } 12 } 13 14 } 15 16 class MyThread extends Thread { 17 18 public void run() { 19 try{ 20 for(int i=0;i<5000;i++){ 21 System.out.println(i); 22 } 23 }catch(Exception e){ 24 e.printStackTrace(); 25 } 26 } 27 }
運行結果:
1 .... 2 4992 3 4993 4 4994 5 4995 6 4996 7 4997 8 4998 9 4999
說明在調用了interrupt之後,線程並不會停止。
使用interrupted()和isInterrupted()判斷中斷狀態
interrupted()作用於調用該方法所在的線程,而不是調用者所在的線程,即無論哪個線程對象調用interrupted()方法,最後結果都是該方法所線上程的狀態結果。
isInterrupted()作用於調用該方法的線程,即誰調用顯示誰的中斷狀態。
並且interrupted()在第二次調用的時候,會恢複線程的狀態,即第一次調用如果是中斷狀態,第二次調用將恢復為非中斷狀態。
而isInterruted()僅僅是查看線程的中斷狀態,並不會改變狀態。請看下麵例子
1 public class App { 2 public static void main(String[] args) { 3 4 try { 5 MyThread thread = new MyThread(); 6 thread.start(); 7 thread.interrupt(); 8 9 //顯示的是主線程的中斷狀態,所以顯示false 10 System.out.println("調用interrupted(): " + thread.interrupted()); 11 12 //main主線程調用interrupt(),是主線程狀態為中斷 13 Thread.currentThread().interrupt(); 14 15 //這裡也可以使用Thread.currentThread().interrupted(),效果是一樣的,具體原因看上面介紹 16 System.out.println("第一次調用interrupted(): " + thread.interrupted()); 17 //第二次調用,interrupted()方法又將狀態恢復 18 System.out.println("第二次調用interrupted(): " + thread.interrupted()); 19 20 System.out.println("-------------------------------------------------"); 21 22 //而isInterrupted()返回的是調用者線程的中斷狀態,而且多次調用狀態不會恢復 23 System.out.println("第一次調用isInterrupted(): " + thread.isInterrupted()); 24 System.out.println("第二次調用isInterrupted(): " + thread.isInterrupted()); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } 28 } 29 } 30 31 class MyThread extends Thread { 32 33 public void run() { 34 try{ 35 while(true){ 36 37 } 38 }catch(Exception e){ 39 e.printStackTrace(); 40 } 41 } 42 }
運行結果為:
1 調用interrupted(): false 2 第一次調用interrupted(): true 3 第二次調用interrupted(): false 4 ------------------------------------------------- 5 第一次調用isInterrupted(): true 6 第二次調用isInterrupted(): true
註意:如果線程在睡眠狀態中,線程狀態被修改為interrupted,這是將拋出java.lang.InterruptedException異常,線程將會停止。
下麵進入正題,如何正確的停止一個線程
有以下幾個方式:
使用break停止線程:判斷線程狀態為中斷時,使用break跳出run()方法中的迴圈,缺點是雖然跳出了迴圈體,但是迴圈體外的程式還會得到執行,並不能到達立即停止的效果
使用return停止線程:判斷線程狀態為中斷時,使用return退出run()方法
拋出異常停止線程:通過拋出一個異常來停止線程,這是比較推薦的方式
這三種方式實現基本相似,我就拿異常法進行舉例了(偷懶)。
1 public class App { 2 public static void main(String[] args) { 3 4 try { 5 MyThread thread = new MyThread(); 6 7 thread.start(); 8 Thread.sleep(2000); 9 thread.interrupt(); 10 11 while(true){ //主線程將一直運行 12 13 } 14 } catch(Exception e){ 15 e.printStackTrace(); 16 } 17 } 18 } 19 20 class MyThread extends Thread { 21 22 public void run() { 23 try{ 24 while(true){ 25 if(isInterrupted()){ 26 throw new InterruptedException(); 27 } 28 } 29 }catch(InterruptedException e){ 30 System.out.println("由於異常退出線程"); 31 e.printStackTrace(); 32 }finally{ 33 System.out.println("這是線程的finally"); 34 } 35 } 36 }
運行結果:
1 java.lang.InterruptedException 2 at com.sunyong.thread.stop.MyThread.run(App.java:31) 3 由於異常退出線程 4 這是線程的finally