來至《java多線程設計模式》
1.wait
(1)調用wait方法必須先獲得對象執行個體的鎖;
(2)可以再synchronized方法中,或synchronized塊中或兩者調用的別的方法中;
(3)執行wait方法的線程會進入obj的wait set裡面,進入之後就已經釋放obj的鎖;
(4)被notify或notifyAll所喚醒的線程會前進到wait的下一個語句。
2.nofify和notifyAll
(1)從obj的wait set中喚醒一個或所有線程(它們試圖去擷取obj的鎖),但是喚醒它(們)之後,該線程仍未釋放該鎖
(2)wait,notify,notifyAll為object類的方法,對執行個體的wait set進行操作。
3.sleep
(1)為線程類方法,讓線程進入阻塞狀態,得不到CPU時間,時間一過重新進入可執行狀態。但sleep方法不會釋放對象的鎖。
(2)只能控制當前正在啟動並執行線程。
4.yield
(1)暫停當前正在執行的線程對象,並執行其他線程,讓當前啟動並執行線程回到可運行狀態,並允許具有相同優先順序的其他線程獲得運行機會。
(2)但它可能未讓步而重新被發送器選中。
5.join
(1)讓一個線程B加入到另一個線程A的尾部。
(2)A執行完畢之前,B不能工作。
二、調用interrupt()的影響:
1.對sleep
任何線程在任何時刻都可以調用其他線程的interrupt方法,被interrupt後放棄暫停狀態,拋出異常。
2.對wait
若obj已經在wait set中,interrupt方法會使線程重新獲得鎖再拋出異常,若未能獲得鎖定,則無法拋出異常。
執行interrupt時無需獲得對該線程的鎖定。
3.join
調用joion方法,無需獲得鎖定,馬上跳到catch塊裡。
三、調用interrupt方法不一定會拋出interruptException:
(1)若調用時,不是在執行sleep/wait/join則不會拋出異常,只是改變中斷狀態;
(2)若調用時,是在執行sleep/wait/join則拋出異常。
// 作業 private void doWork() throws InterruptedException { counter++; System.out.println("doWork: counter = " + counter); try { Thread.sleep(500); } catch (InterruptedException e) { } }
以上若調用interrupt則無法中斷。
System.out.println("main: shutdownRequest"); t.shutdownRequest();
必須如下:
// 作業 private void doWork() throws InterruptedException { counter++; System.out.println("doWork: counter = " + counter); Thread.sleep(500); }
則可以正常終止。
在調用doWork的地方進行捕獲:
// 動作 public void run() { try { while (!isInterrupted()) { doWork(); } } catch (InterruptedException e) { } finally { doShutdown(); } }
// 終止請求 public void shutdownRequest() { interrupt(); }
上面那個捕獲異常之後沒有處理,所以在run裡面無法捕獲,無法執行doShutdown方法來停止。
對比:
public synchronized Request getRequest() throws InterruptedException { while (queue.size() <= 0) { wait(); } return (Request)queue.removeFirst(); }
這裡拋出異常,同時在調用的地方進行捕獲,並且退出run
public void run() { try { for (int i = 0; i < 10000; i++) { Request request = new Request("No." + i); System.out.println(Thread.currentThread().getName() + " requests " + request); requestQueue.putRequest(request); Thread.sleep(random.nextInt(1000)); } } catch (InterruptedException e) { } }
調用時,是直接interrupt:
//呼叫interrupt方法 System.out.println("***** calling interrupt *****"); alice.interrupt(); bobby.interrupt();