這三個線程的方法,我理解了很久,很是容易搞混,這裏有個圖大家可以先看一下。
我首先碰到線程中斷是因爲一個面試題,中斷線程的方法,你能說出幾種?怎麼優雅的中斷線程?下面是我的理解
- 使用退出標誌,使線程正常退出,也就是當 run 方法完成 後線程終止。(優雅)
public class ServerThread extends Thread { //volatile修飾符用來保證其它線程讀取的總是該變量的最新的值 public volatile boolean exit = false; @Override public void run() { ServerSocket serverSocket = new ServerSocket(8080); while(!exit){ serverSocket.accept(); //阻塞等待客戶端消息 ... } } public static void main(String[] args) { ServerThread t = new ServerThread(); t.start(); ... t.exit = true; //修改標誌位,退出線程 } }
- 通過return 退出 run 方法
/** * Created by edison on 2017/12/3. */ public class MyThread12 extends Thread{ @Override public void run() { super.run(); for (int i = 0; i < 50000; i++) { if (Thread.interrupted()) { System.out.println("子線程已經停止了,我要退出"); return; } System.out.println("i="+(i+1)); } System.out.println("for循環後繼續執行"); } }
- 通過stop終止線程,就象突然關 閉計算機電源,而不是按正常程序關機一樣,可能會產生不可預料的結果用 stop() 方法會立刻停止 run() 方法中剩餘的全部工作,包括在 catch 或 finally 語句中的,並拋出ThreadDeath異常(通常情況下此異常不需要顯示的捕獲),因此可能會導致一些清理性的工作的得不到完成,如文件,數據庫等的關閉。已經被棄用。
- Interrupt 方法結束線程。Thread.interrupt()方法: 作用是中斷線程。將會設置該線程的中斷狀態位,即設置爲true,中斷的結果線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決於這個程序本身。線程會不時地檢測這個中斷標示位,以判斷線程是否應該被中斷(中斷標示值是否爲true)。它並不像stop方法那樣會中斷一個正在運行的線程。interrupt()方法只是改變中斷狀態,不會中斷一個正在運行的線程。
public class InterruptionInJava implements Runnable{ public static void main(String[] args) throws InterruptedException { Thread testThread = new Thread(new InterruptionInJava(),"InterruptionInJava"); //start thread testThread.start(); Thread.sleep(1000); //interrupt thread testThread.interrupt(); System.out.println("main end"); } @Override public void run() { while(true){ if(Thread.currentThread().isInterrupted()){ System.out.println("Yes,I am interruted,but I am still running"); }else{ System.out.println("not yet interrupted"); } } } }
結果顯示,被中斷後,仍舊運行,不停打印Yes,I am interruted,but I am still running
在理解interrupt和interruped、isinterruped時,我覺得遇到了一定的麻煩,我不明白,爲什麼interrupt方法作用是中斷線程,但是不會中斷一個正在運行的線程是什麼意思?這不是自相矛盾嗎?
通過之後的查閱資料,我明白了,其實也很簡單,在調用interrupt方法時,線程有且僅有兩種狀態,
第一種:線程是running狀態。
當線程處於第一種狀態時,將線程的中斷標記爲true,就是說,線程可以被中斷啦,是否中斷是他自己的事。
在這裏,我又有疑問了,調用interrupt方法不是要結束線程嗎?爲什麼只標記可以被中斷,爲什麼不中斷,怎麼中斷?
當然可以通過return,但是要做的更通用,可以使用中斷標記,其實這兩種不需要調用interrupt方法就可以中斷線程。利用線程中斷異常就是一個很好的辦法,既然是異常,通常異常可以中斷線程的運行,使程序掛掉,我們自己拋出一個異常讓線程中斷。也可以使用sleep或wait阻塞方法,讓程序出現阻塞,拋出InterruptException異常。
class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
if (this.interrupted()) {
System.out.println("should be stopped and exit");
throw new InterruptedException();
}
System.out.println("i=" + (i + 1));
}
System.out.println("this line cannot be executed. cause thread throws exception");//這行語句不會被執行!!!
} catch (InterruptedException e) {
System.out.println("catch interrupted exception");
e.printStackTrace();
}
}
}
package cn.itcast.thread;
public class Interrupt {
public static void main(String[] args) {
A a = new A();
Thread t1 = new Thread(a);
t1.start();
t1.interrupt();
System.out.println("執行睡眠之前1:"+t1.isInterrupted());
try {
System.out.println("執行睡眠之前2:"+t1.isInterrupted());
Thread.sleep(1000);//線程進入阻塞狀態
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("執行睡眠之後:"+t1.isInterrupted());
}
}
}
class A implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread());
}
}
第二種:線程是阻塞狀態(使用了sleep、wait等方法時)。
當線程處於阻塞狀態時,調用線程的 interrupt()方法時,會拋出 InterruptException 異常。 阻塞中的那個方法拋出這個異常,通過代碼捕獲該異常,然後 break 跳出循環狀態,從而讓 我們有機會結束這個線程的執行。
而interruped、isinterruped方法的目的只是判斷線程是否中斷,沒有中斷線程的作用。只是interruped方法在檢測到線程中斷狀態爲true之後,返回true,之後又把中斷狀態清除了,恢復到了默認的false狀態,所以第二次調用的時候就是false狀態了。
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!");
}
}