Markdown版本筆記 | 我的GitHub首頁 | 我的博客 | 我的微信 | 我的郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目錄
如何安全的結束一個正在運行的線程
Thread類相關的方法
使用退出標志
使用 interrupt 方法
使用 interrupt() + InterruptedException
使用 interrupt() + isInterrupted()
一個綜合案例
不能結束的情況
如何安全的結束一個正在運行的線程
Thread類相關的方法
java.lang.Thread
類包含了一些常用的方法,如:start(), stop(), stop(Throwable) ,suspend(), destroy() ,resume()。通過這些方法,我們可以對線程進行方便的操作,但是這些方法中,只有start()
方法得到了保留。
在JDK幫助文檔以及Sun公司的一篇文章《Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?》
中都講解了舍棄這些方法的原因。
簡單來說是因為:使用stop方法雖然可以強行終止
正在運行或掛起的線程,但使用stop方法是很危險
的,就象突然關閉計算機電源,而不是按正常程序關機一樣,可能會產生不可預料的結果,因此,並不推薦使用stop方法來終止線程。
那么,我們究竟應該如何停止線程呢?
- 1、任務中一般都會有循環結構,只要用一個標記控制住循環,就可以結束任務。
- 2、如果線程處於了
凍結狀態
,無法讀取標記,此時可以使用interrupt()
方法將線程從凍結狀態強制恢復到運行狀態中
來,讓線程具備CPU的執行資格。
使用退出標志
當run方法執行完后,線程就會退出。但有時run方法是永遠不會結束的,如在服務端程序中使用線程進行監聽客戶端請求,或是其他的需要循環處理的任務。
在這種情況下,一般是將這些任務放在一個循環中,如while循環。如果想使while循環在某一特定條件下退出,最直接的方法就是設一個boolean類型的標志,並通過設置這個標志為true或false來控制while循環是否退出。
public class Test {
public static volatile boolean exit = false;//退出標志
public static void main(String[] args) {
new Thread() {
public void run() {
System.out.println("線程啟動了");
while (!exit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("線程結束了");
};
}.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
exit = true;//5秒后更改退出標志的值
}
}
使用 interrupt 方法
如果一個線程由於等待某些事件的發生而被阻塞,又該怎樣停止該線程呢?
這種情況經常會發生,比如當一個線程由於需要等候鍵盤輸入而被阻塞,或者調用Thread.join()
方法,或者Thread.sleep()
方法,在網絡中調用ServerSocket.accept()
方法,或者調用了DatagramSocket.receive()
方法時,都有可能導致線程阻塞,使線程處於處於不可運行狀態
時,即使主程序中將該線程的共享變量設置為true,但該線程此時根本無法檢查循環標志,當然也就無法立即中斷。
這時建議不要使用stop()方法,而是使用Thread提供的interrupt()
方法,因為該方法雖然不會中斷一個正在運行的線程,但是它可以使一個被阻塞的線程拋出一個中斷異常,從而使線程提前結束阻塞狀態,退出堵塞代碼
。
使用 interrupt() + InterruptedException
線程處於阻塞狀態,如Thread.sleep、wait、IO阻塞
等情況時,調用interrupt方法后,sleep等方法將會拋出一個InterruptedException:
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("線程啟動了");
try {
Thread.sleep(1000 * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程結束了");
}
};
thread.start();
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//作用是:在線程阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態
}
}
使用 interrupt() + isInterrupted()
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("線程啟動了");
while (!isInterrupted()) {
System.out.println(isInterrupted());//調用 interrupt 之后為true
}
System.out.println("線程結束了");
}
};
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("線程是否被中斷:" + thread.isInterrupted());//true
}
}
一個綜合案例
public class Test {
static boolean flag = true;
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("開始休眠");
try {
Thread.sleep(100 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("結束休眠,開始死循環");
while (flag) {
}
System.out.println("------------------子線程結束------------------");
}
});
thread.start();
Scanner scanner = new Scanner(System.in);
System.out.println("輸入1拋出一個中斷異常,輸入2修改循環標志位,輸入3判斷線程是否阻塞,輸入其他結束Scanner\n");
while (scanner.hasNext()) {
String text = scanner.next();
System.out.println("你輸入了:" + text + "\n");
if ("1".equals(text)) {
thread.interrupt();
} else if ("2".equals(text)) {
flag = false; //如果不設為false,主線程結束后子線程仍在運行
} else if ("3".equals(text)) {
System.out.println(thread.isInterrupted());
} else {
scanner.close();
break;
}
}
System.out.println("------------------主線程結束------------------");
}
}
不能結束的情況
注意下面這種是根本不能結束的情況!
public class Test {
public static void main(String[] args) {
Thread thread = new Thread() {
public void run() {
System.out.println("線程啟動了");
while (true) {//對於這種情況,即使線程調用了intentrupt()方法並且isInterrupted(),但線程還是會繼續運行,根本停不下來!
System.out.println(isInterrupted());//調用interrupt之后為true
}
}
};
thread.start();
thread.interrupt();//注意,此方法不會中斷一個正在運行的線程,它的作用是:在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態
while (true) {
System.out.println("是否isInterrupted:" + thread.isInterrupted());//true
}
}
}
2019-5-8