停止一個線程的主要機制是中斷,中斷並不代表強迫終止一個線程,
它是一種協作機制,是給線程傳遞一個取消的信號,
但是讓線程來決定如何以及何時退出。
這句話可謂是線程中斷的核心原理了;光看文字還是很模糊的,用代碼說事吧。
1 public class ThreadEnd implements Runnable { 2 3 private volatile static boolean ok=false; 4 @Override 5 public void run() { 6 for(;;){ 7 if(Thread.currentThread().isInterrupted()){ 8 System.out.println("我進入了中斷線程的條件中,將要結束run方法"); 9 break;//因為是for死循環,用這種方式退出循環 10 }else{ 11 System.out.println("我沒有收到中斷信息"); 12 } 13 } 14 } 15 16 17 18 public static void main(String[] args) throws InterruptedException { 19 Thread thread = new Thread(new ThreadEnd()); 20 thread.start(); 21 Thread.sleep(1000); 22 thread.interrupt(); 23 System.out.println("主線程結束"); 24 25 } 26 }
在第6行中不停的死循環來查看線程 isInterrupted()方法是否返回true;
第22行代碼給線程調用了線程中斷方法,第7行條件滿足,最終退出線程。
那么有一個疑問:是不是所有的線程都可以用interrupt()方法進行中斷呢?
比如說sleep的線程,比如說等待鎖的線程?我們挨個來求解吧。
sleep休眠線程中斷代碼
1 public class InterruptionSleepThread implements Runnable { 2 3 @Override 4 public void run() { 5 try { 6 System.out.println("本大爺要休眠50秒,你能奈我何?"); 7 Thread.sleep(50000);//休眠50秒 8 } catch (InterruptedException e) { 9 System.out.println("休眠的線程收到中斷信號,利用拋異常的方式將本大爺從夢中叫醒,結束線程。"); 10 e.printStackTrace(); 11 } 12 } 13 public static void main(String[] args) throws InterruptedException { 14 Thread thread = new Thread(new InterruptionSleepThread()); 15 thread.start(); 16 Thread.sleep(2000); 17 thread.interrupt(); 18 System.out.println("主線程結束"); 19 20 } 21 }
打印結果
從上面的打印結果來看,休眠的線程是的確退出來了,雖然這個叫醒的方式不怎么優雅(異常的方式)。
這也從另外一個角度告訴了我們,為什么每次在run()里面調用sleep()方法的時候,編譯器要我們強制進行異常捕獲了,也是為了程序安全。
等待鎖的過程中,被中斷的代碼
1 public class WaitLockThreadInterrupted extends Thread { 2 3 private static Object lock =new Object(); 4 5 @Override 6 public void run() { 7 System.out.println("我要等待test鎖釋放后,才能執行下面的代碼"); 8 synchronized (lock){ 9 while (true){ 10 if(Thread.currentThread().isInterrupted()){ 11 System.out.println("我收到線程中斷的信號"); 12 break; 13 }else{ 14 System.out.println("沒收到線程中斷的信號"); 15 } 16 } 17 } 18 } 19 20 private static void test() throws InterruptedException { 21 synchronized (lock){ 22 Thread thread=new Thread(new WaitLockThreadInterrupted()); 23 thread.start(); 24 Thread.sleep(1000); 25 thread.interrupt(); 26 System.out.println("已發出中斷信號"); 27 thread.join();//阻塞test方法,一直到線程thread執行完畢。 28 } 29 } 30 31 public static void main(String[] args) throws InterruptedException { 32 test(); 33 } 34 }
打印結果
雖然打印了結果,但是左邊的紅燈一直亮着,並且也沒有打印11行的內容,表示線程一直沒有退出來。
分析代碼:test中的synchronized()和run方法中的synchronized用了同一個對象鎖,
所以22行的thread線程中的run方法的執行,必須等到test釋放掉lock鎖對象才行;
但是 test中用thread.join()方法來告訴我們,等thread線程執行完畢了,我才能放你們走。
完了,死鎖了。
這種死鎖的狀態如果25行代碼發出中斷信號有用的話,這種死鎖的尷尬是能夠解開的。
從打印結果來看 interrupt()是不能中斷等待鎖的線程的。
結論:
1.Runnable狀態(正在運行或者等待調度的線程)可以用interrupt()中斷
2.Block狀態(等待鎖的線程)不可以用interrupt()中斷