<Java><Multi-thread>
Overview
- notify() VS notifyAll()
From a basic example
- 一個最經典的生產者消費者模型:
-
public synchronized void put(String value) throws InterruptedException{ while (buffer.size() == capacity) { System.out.println(Thread.currentThread().getName() + " is waiting..."); wait(); } buffer.add(value); System.out.println(Thread.currentThread().getName() + " has produced " + value); notify(); } public synchronized String get() throws InterruptedException{ while (buffer.size() == 0) { System.out.println(Thread.currentThread().getName() + " is waiting..."); wait(); } String val = buffer.remove(0); notify(); System.out.println(Thread.currentThread().getName() + " has consumed " + val); return val; }
- 首先,第一個問題是,為什麽get和put內部都要用while循環?答:We need a
while
loop in case we get this situation:- c1進入臨界區,發現size為空,於是wait;
- p1進入臨界區,增加了buffer,並notify;
- 同時,c2也在等待進入臨界區(block阻塞狀態);
- c1被notified,但是c1未搶占到鎖,因為c2進入了臨界區,消費了buffer,之後buffer又為空;
- 之後,c1擁有了鎖,但此時buffer已經為空,所以必須有while循環,再次判斷。
- 然後,為什麽需要notifyAll()?
- 我們都知道notify()是通知一個線程,而notifyAll()是通知所有線程。具體說來又有什麽區別呢?
- 考慮一個buffer為1的隊列(for simplicity):
-
STEP 1:
- P1 puts 1 char into the bufferSTEP 2:
- P2 attemptsput
- checks wait loop - already a char - waits 【P2在等待】STEP 3:
- P3 attemptsput
- checks wait loop - already a char - waits 【P2、P3在等待】STEP 4:
- C1 attempts to get 1 char
- C2 attempts to get 1 char - blocks on entry to theget
- C3 attempts to get 1 char - blocks on entry to theget
method 【C2、C3阻塞】STEP 5:
- C1 is executing theget
method - gets the char, callsnotify
, exits method
- Thenotify
wakes up P2
- BUT, C2 enters method before P2 can (P2 must reacquire the lock), so P2 blocks on entry to theput
method 【P3等待】【P2、C3阻塞】
- C2 checks wait loop, no more chars in buffer, so waits 【P3、C2等待】【P2、C3阻塞】
- C3 enters method after C2, but before P2, checks wait loop, no more chars in buffer, so waits 【C3、C2、P3等待】【P2阻塞】STEP 6:
- NOW: there is P3, C2, and C3 waiting!
- Finally P2 acquires the lock, puts a char in the buffer, calls notify, exits method 【P2終於搶占了鎖】STEP 7:
- P2‘s notification wakes P3 (remember any thread can be woken) 【P3被notified】
- P3 checks the wait loop condition, there is already a char in the buffer, so waits. 【P3、C2、C3等待】【阻塞隊列為空】
- NO MORE THREADS TO CALL NOTIFY and THREE THREADS PERMANENTLY SUSPENDED! - 上述死鎖問題的解決方案就是:把所有的notify()換成notifyAll()。從而每次都能notifyAll把所有在等待的線程都變成阻塞狀態。
- 以上,實際上就是造成了blocked和wait這兩個狀態之間的區別。
FYI
- stackOverflow
<Java><Multi-thread>