前言
Thread的實例方法stop()用來中止線程,它是真正的中止線程,與之相對應的interrupt()是一種提示性中止,因爲沒有留出機會讓程序員處理資源,stop()會帶來狀態一致性問題,所以已不推薦使用,不過這裏是爲了探究爲什麼不推薦使用,所以研究。
中止線程
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("begin");
try {
this.stop();
} catch (ThreadDeath e) {
System.out.println("進入catch塊了");
e.printStackTrace();
}
System.out.println("end");
}
}
public class StopRun {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
}
}
輸出結果
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:850)
at extthread.MyThread.run(MyThread.java:13)
begin
進入catch塊了
end
根據java api所述,
無論該線程在做些什麼,它所代表的線程都被迫異常停止,並拋出一個新創建的 ThreadDeath 對象,作爲異常。
通過輸出可以看到的確拋出了ThreadDeath,以上示例是參考《Java多線程編程核心技術》一書所寫,在實踐中我稍微改了一下卻發現,沒有任何異常信息。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("begin");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
}
}
public class StopRun {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
//讓myThread得到機會運行
Thread.sleep(200);
myThread.stop();
}
}
此種寫法,控制檯什麼也沒輸出!當時我就納悶了?不應該呀,按照api,stop()方法肯定會拋出ThreadDeath。後來一想,拋出的異常應該在目標線程拋出,而非執行線程拋出,在本例中myThread是目標線程,主線程是執行線程。果斷將MyThread的run()方法,try catch,經此一改,果然出現異常信息了
@Override
public void run() {
try {
System.out.println("begin");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}catch (ThreadDeath e){
e.printStackTrace();
}
System.out.println("end");
}
輸出結果
begin
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:850)
at test.StopRun.main(StopRun.java:14)
end
ThreadDeath
順便提一下ThreadDeath,按照api規定,stop()時會拋出ThreadDeath,ThreadDeath是繼承自Error,而非Exception子類,通常情況下,是不需要catch的,上邊的例子只是爲了演示,所以catch。所以在catch時,應該catch(Error)或者catch(ThreadDeath),而不應該catch(Exception),catch(Exception)也不會打印異常信息。
狀態一致性問題
stop()屬於暴力強制中止線程,會帶來狀態一致性問題。
public class SynchronizedObject {
private String userName = "a";
private String password = "aa";
public synchronized void printString(String userName, String password){
try {
this.userName = userName;
Thread.sleep(100000);
this.password = password;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class SynchronizedThread extends Thread {
private SynchronizedObject object;
public SynchronizedThread(SynchronizedObject object) {
this.object = object;
}
@Override
public void run() {
object.printString("b","bbb");
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedObject object = new SynchronizedObject();
SynchronizedThread t = new SynchronizedThread(object);
t.start();
Thread.sleep(500);
t.stop();
System.out.println(object.getUserName()+"-"+object.getPassword());
}
輸出結果,可以看到因爲stop()的強制中止,沒有給程序員預留善後空間,導致狀態不一致;理論上,使用stop()的地方都應該使用interrupt()代替;
b-aa
參考
java多線程編程核心技術 高洪巖著