新建、可運行、死亡、**阻塞**。阻塞狀態最有趣,值得深入探討。
resume() 不會回「可運行」notify()/notifyAll() 不會變「可運行」(與原因 2 相似但有明顯區別)yield() 自動放棄 CPU 讓其他執行緒運行。但若調度器覺得我們執行緒已擁有足夠時間並跳轉到另一執行緒,會發生同樣事。沒有什麼能防止調度器重新啟動我們的執行緒。**阻塞後有具體原因導致無法繼續運行**。
所有類別存在於 Blocking.java,此處用片段解釋。
class Blockable extends Thread {
private Peeker peeker;
protected TextField state = new TextField(40);
protected int i;
public Blockable(Container c) { c.add(state); peeker = new Peeker(this, c); }
public synchronized int read() { return i; }
protected synchronized void update() { state.setText(getClass().getName() + " state: i = " + i); }
public void stopPeeker() { peeker.terminate(); }
}
class Peeker extends Thread {
private Blockable b;
private int session;
private TextField status = new TextField(40);
private boolean stop = false;
public Peeker(Blockable b, Container c) { c.add(status); this.b = b; start(); }
public void terminate() { stop = true; }
public void run() {
while (!stop) {
status.setText(b.getClass().getName() + " Peeker " + (++session) + "; value = " + b.read());
try { sleep(100); } catch (InterruptedException e){}
}
}
}
Blockable:基礎類,含 state 顯示資訊,update() 用 getClass().getName() 取得確切類名int i,衍生類 run() 遞增Blockable 啟動一個 Peeker 執行緒,定期呼叫 read() 檢查 i 變化並報告read() 和 update() 皆同步,要求物件鎖可自由釋放——**極重要**class Sleeper1 extends Blockable {
public synchronized void run() { // 整個 run 同步
while(true) { i++; update(); try { sleep(1000); } catch (InterruptedException e){} }
}
}
class Sleeper2 extends Blockable {
public void run() { // 不同步 run
while(true) { change(); try { sleep(1000); } catch (InterruptedException e){} }
}
public synchronized void change() { i++; update(); }
}
run() 同步 → 啟動後 Peeker 完全停止(鎖永不釋放)change() 同步 → Peeker 持續運行(sleep() 期間鎖已釋放)class SuspendResume1 extends Blockable {
public synchronized void run() { while(true) { i++; update(); suspend(); } }
}
class SuspendResume2 extends Blockable {
public void run() { while(true) { change(); suspend(); } }
public synchronized void change() { i++; update(); }
}
class Resumer extends Thread { // 獨立恢復器
private SuspendResume sr;
public void run() { while(true) { try { sleep(1000); } catch (InterruptedException e){} sr.resume(); } }
}
run() 導致 Peeker 阻塞;分離同步方法解決suspend() 持有物件鎖,極易死結class WaitNotify1 extends Blockable {
public synchronized void run() { while(true) { i++; update(); try { wait(1000); } catch (InterruptedException e){} } }
}
class WaitNotify2 extends Blockable {
public synchronized void run() { while(true) { i++; update(); try { wait(); } catch (InterruptedException e){} } }
}
class Notifier extends Thread {
private WaitNotify2 wn2;
public void run() { while(true) { try { sleep(2000); } catch (InterruptedException e){} synchronized(wn2) { wn2.notify(); } } }
}
wait() 被調用時**釋放鎖定**!執行期間可調用其他同步方法wait(毫秒) 定時/可被 notify() 強制結束;wait() 無限期直到 notify()wait()/notify() 屬於 Object 基礎類(操縱物件鎖),非 ThreadIllegalMonitorStateExceptionsynchronized(other) { other.notify(); } 為他人鎖操作class Sender extends Blockable {
private Writer out;
public void run() {
while(true) {
for(char c = 'A'; c <= 'z'; c++) {
try { i++; out.write(c); state.setText("Sender sent: " + c); sleep((int)(3000 * Math.random())); }
catch (InterruptedException e){} catch (IOException e) {}
}
}
}
}
class Receiver extends Blockable {
private Reader in;
public void run() {
try { while(true) { i++; state.setText("Receiver read: " + (char)in.read()); } }
catch(IOException e) { e.printStackTrace(); }
}
}
PipedWriter/PipedReader 連接兩執行緒Receiver 無 sleep/suspend/wait,但執行 read() 時無資料 → **自動阻塞**建立 Blockable 陣列,按下「Start」啟動所有執行緒。「Stop Peekers」示範 Thread.stop() 替代方案。Sender/Receiver 用管道串流連接。初始化時每個 Blockable 自動建立並啟動 Peeker,**部分 Peeker 會在 Blockable 啟動時被阻塞停止運行**——理解此點加深對「阻塞」認識。