最近打算讀一下《實戰java高并發程序設計》,夯實一下java多線程的知識。接下來應該會寫一系列的讀書筆記,里面會有多處引用到書中的代碼或者文字。本文就是第一篇。
不推薦使用的stop方法
Thread.stop()是一個被廢棄的方法,不被推薦使用的原因是stop方法太過于暴力,強行把執行到一半的線程終止,并且會立即釋放這個線程所有的鎖。會破壞了線程中引用對象的一致性。
例如在數據庫中維護著一張用戶表,記錄了用戶ID和用戶名,使用Thread多線程寫入兩條記錄:
記錄1: ID=1,NAME=小明
記錄2: ID=2,NAME=小王
如果在記錄1寫到一半的時候被stop結束了,就可能出現各種奇怪的現象:
- 記錄1被記錄2覆蓋,沒有任何數據留下。
- 記錄1只有一半,即只有ID,而NAME為空。
- 記錄1和記錄2混在同一條記錄中,最后寫入了一條一半是記錄1一半是記錄2的臟數據
所以,除非你很確定你在做什么,否則不要輕易使用stop方法
使用判斷標志位的方法中斷線程
那如果的確有中斷線程的需求,我們需要怎么做呢?一般我們馬上就會想到設置標志位的方法,即在線程中執行每一個步驟之前都判斷一下是否需要退出線程:
class WorkThread extends Thread {
private boolean mExitThread = false;
public void exitThread() {
mExitThread = true;
}
@Override
public void run() {
if (mExitThread) {
return;
}
//do something
if (mExitThread) {
return;
}
//do something
if (mExitThread) {
return;
}
//do something
}
}
其實Thread類早就幫我們實現了這個中斷標志了。與Thread中斷相關的方法有下面三個:
public void Thread.interrupt() //線程中斷
public native boolean Thread.isInterrupted() //判斷是否被中斷
public static native boolean Thread.interrupted() //判斷是否中斷,并清除當前中斷狀態
所以上面的代碼可以改寫成這樣:
class WorkThread extends Thread {
@Override
public void run() {
if (isInterrupted()) {
return;
}
//do something
if (isInterrupted()) {
return;
}
//do something
if (isInterrupted()) {
return;
}
//do something
}
}
這個時候我們只需要調用Thread.interrupt()方法就能安全的中斷線程了。
需要提醒一下的是Thread.interrupt()方法并不會像Thread.stop()方法一樣立即結束線程,它只是設置了一個中斷標志,需要在代碼實現中去手動判斷這個標志并且推出。
像下面這個代碼就算掉了Thread.interrupt()方法也不會中斷線程:
class WorkThread extends Thread {
@Override
public void run() {
while(true){
//do something
}
}
}
Thread.interrupt的優點
使用Thread.interrupt去中斷線程除了可以免去自己實現標志位的煩惱之外,還可以中斷sleep和wait中的線程。
還記得我們在調用Thread.sleep()這個方法的時候都需要catch或者拋出InterruptedException這個異常嗎:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
這個InterruptedException異常就是由于我們調用了Thread.interrupt方法拋出的。所以Thread.interrupt可以打斷Thread.sleep。同樣Thread.wait也是可以被Thread.interrupt打斷的。
需要注意的是如果sleep方法由于中斷而拋出異常,此時,它會清除中斷標記。所以在catch到這個異常的時候需要再次設置中斷標記:
Thread t1 = new Thread() {
@Override
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
break;
}
System.out.println("hello world");
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
};