首页 > 代码库 > <Java><Multi-thread>
<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
method 【C2阻塞】
- 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>