不提倡的stop()方法
臭名昭著的stop()停止線程的方法已不提倡使用了,原因是什麼呢?
當在一個線程對象上調用stop()方法時,這個線程對象所啟動並執行線程就會立即停止,並拋出特殊的ThreadDeath()異常。這裡的“立即”因為太“立即”了,
假如一個線程正在執行:
synchronized void {
x = 3;
y = 4;
}
由於方法是同步的,多個線程訪問時總能保證x,y被同時賦值,而如果一個線程正在執行到x = 3;時,被調用了 stop()方法,即使在同步塊中,它也乾脆地stop了,這樣就產生了不完整的殘廢資料。而多線程編程中最最基礎的條件要保證資料的完整性,所以請忘記 線程的stop方法,以後我們再也不要說“停止線程”了。
如何才能“結束”一個線程?
interupt()中斷線程
一個線程從運行到真正的結束,應該有三個階段:
- 正常運行.
- 處理結束前的工作,也就是準備結束.
- 結束退出.
那麼如何讓一個線程結束呢?既然不能調用stop,可用的只的interrupt()方法。但interrupt()方法只是改變了線程的運行狀態,如何讓它退出運行?對於一般邏輯,只要線程狀態已經中斷,我們就可以讓它退出,這裡我們定義一個線程類ThreadA,所以這樣的語句可以保證線程在中斷後就能結束運行:
while(!isInterrupted()){
正常邏輯
}
,一個測試類別,ThreadDemo
這樣ThreadDemo調用interrupt()方法,isInterrupted()為true,就會退出運行。但是如果線程正在執行wait,sleep,join方法,你調用interrupt()方法,這個邏輯就不完全了。
我們可以這樣處理:
public void run(){
while(!isInterrupted()){
try{
正常工作
}catch(InterruptedException e){
//nothing
}
}
}
}
想一想,如果一個正在sleep的線程,在調用interrupt後,會如何?wait方法檢查到isInterrupted()為true,拋出異常, 而你又沒有處理。而一個拋出了InterruptedException的線程的狀態馬上就會被置為非中斷狀態,如果catch語句沒有處理異常,則下一 次迴圈中isInterrupted()為false,線程會繼續執行,可能你N次拋出異常,也無法讓線程停止。
這個錯誤情況的執行個體代碼
ThreadA
public class ThreadA extends Thread ...{
int count=0;
public void run()...{
System.out.println(getName()+"將要運行...");
while(!this.isInterrupted())...{
System.out.println(getName()+"運行中"+count++);
try...{
Thread.sleep(400);
}catch(InterruptedException e)...{
System.out.println(getName()+"從阻塞中退出...");
System.out.println("this.isInterrupted()="+this.isInterrupted());
}
}
System.out.println(getName()+"已經終止!");
}
}
ThreadDemopublic class ThreadDemo ...{
public static void main(String argv[])throws InterruptedException...{
ThreadA ta=new ThreadA();
ta.setName("ThreadA");
ta.start();
Thread.sleep(2000);
System.out.println(ta.getName()+"正在被中斷...");
ta.interrupt();
System.out.println("ta.isInterrupted()="+ta.isInterrupted());
}
}
那麼如何能確保線程真正停止?線上程同步的時候我們有一個叫“二次惰性檢測”(double check),能在提高效率的基礎上又確保線程真正中同步控制中。那麼我把線程正確退出的方法稱為“雙重安全退出”,即不以isInterrupted ()為迴圈條件。而以一個標記作為迴圈條件:
正確的ThreadA代碼是:
public class ThreadA extends Thread ...{
private boolean isInterrupted=false;
int count=0;
public void interrupt()...{
isInterrupted = true;
super.interrupt();
}
public void run()...{
System.out.println(getName()+"將要運行...");
while(!isInterrupted)...{
System.out.println(getName()+"運行中"+count++);
try...{
Thread.sleep(400);
}catch(InterruptedException e)...{
System.out.println(getName()+"從阻塞中退出...");
System.out.println("this.isInterrupted()="+this.isInterrupted());
}
}
System.out.println(getName()+"已經終止!");
}
}