在多线程里面,为什么推荐使用notifyAll而不是notify?
结论:notify容易造成死锁
1、无论使用notify或者notifyAll,都是随机唤醒线程
2、notify是随机唤醒一个线程去执行,noifyAll是唤醒所有线程,然后去抢占锁,去执行
怎么产生死锁现象:
P – 生产者 调用 putproduct C – 消费者 调用 consumer。
-
P2 调用product,发现满了,在wait里面等了。
-
P2 调用product,发现满了,在wait里面等了。
-
P2 调用product,发现满了,在wait里面等了。
-
C1 想来拿,C2,C3 就在 consumer里面等着。
-
C1 开始执行,移除remove,然后调用 notify 然后退出。
- 如果 C1 把 C2 唤醒了,所以P2 (其他的都得等)只能在product方法上等着。
- C2 检查 while 循环发现此时队列是空的,所以就在 wait 里面等着。
- C3 也比 P2 先执行,那么发现也是空的,只能等着了。
-
这时候我们发现 P2、C2、C3 都在等着锁,最终 P2 拿到了锁,放一个 1,notify,然后退出。
-
P2 这个时候唤醒了P3,P3发现队列是满的,没办法,只能等它变为空。 8. 这时候没有别的调用了,那么现在这三个线程(P3, C2,C3)就全部变成 suspend 了,也就是死锁了。
代码示例
public class Thread03{
private Buffer mbuffer = new Buffer();
// private List<Object> list = new ArrayList<>();
public void product(){
synchronized (this) {
while (mbuffer.isFull()){
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
mbuffer.add();
notify();
}
}
public void consumer(){
synchronized (this) {
while (mbuffer.isEmpty()){
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
mbuffer.remove();
notify();
}
}
private class Buffer {
private static final int MAX_CAPACITY = 1;
private List innerList = new ArrayList<>(MAX_CAPACITY);
void add() {
if (isFull()) {
throw new IndexOutOfBoundsException();
} else {
innerList.add(new Object());
}
System.out.println(Thread.currentThread().toString() + " add");
}
void remove() {
if (isEmpty()) {
throw new IndexOutOfBoundsException();
} else {
innerList.remove(MAX_CAPACITY - 1);
}
System.out.println(Thread.currentThread().toString() + " remove");
}
boolean isEmpty() {
return innerList.isEmpty();
}
boolean isFull() {
return innerList.size() == MAX_CAPACITY;
}
}
public static void main(String[] args) {
Thread03 thread03 = new Thread03();
Runnable product = new Runnable() {
int count = 4;
@Override
public void run() {
while (count-- > 0) {
thread03.product();
}
}
};
Runnable consumer = new Runnable(){
@Override
public void run() {
int count = 4;
while (count-- >0){
thread03.consumer();
} }
};
for (int i = 0; i < 2; i++) {
new Thread(product).start();
}
for (int i = 0; i < 2; i++) {
new Thread(consumer).start();
}
}
}
标签:P2,product,notifyAll,void,notify,new,多线程,public
From: https://www.cnblogs.com/snowflow/p/17798120.html