@
rogerchen 这里有一个例子(
http://blog.csdn.net/zhangheliang2010/article/details/44890103)
public class MyStack {
private List<String> list = new ArrayList<String>();
public synchronized void push(String value) {
synchronized (this) {
list.add(value);
notify();
}
}
public synchronized String pop() throws InterruptedException {
synchronized (this) {
if (list.size() <= 0) {
wait();
}
return list.remove(list.size() - 1);
}
}
}
问题: 这段代码大多数情况下运行正常,但是某些情况下会出问题。什么时候会出现什么问题?如何修正?
代码分析:
从整体上,在并发状态下, push 和 pop 都使用了 synchronized 的锁,来实现同步,同步的数据对象是基于 List 的数据;大部分情况下是可以正常工作的。
问题描述:
状况 1 :
1. 假设有三个线程: A,B,C. A 负责放入数据到 list,就是调用 push 操作, B,C 分别执行 Pop 操作,移除数据。
2. 首先 B 先执行,于 pop 中的 wait()方法处,进入 waiting 状态,进入等待队列,释放锁。
3. A 首先执行放入数据 push 操作到 List ,在调用 notify()之前; 同时 C 执行 pop(),由于 synchronized ,被阻塞,进入 Blocked 状态,放入基于锁的等待队列。注意,这里的队列和 2 中的 waiting 等待队列是两个不同的队列。
4. A 线程调用 notify(),唤醒等待中的线程 A 。
5. 如果此时, C 获取到基于对象的锁,则优先执行,执行 pop 方法,获取数据,从 list 移除一个元素。
6. 然后, A 获取到竞争锁, A 中调用 list.remove(list.size() - 1),则会报数据越界 exception 。
状况 2 :
1. 相同于状况 1
2. B 、 C 都处于等待 waiting 状态,释放锁。等待 notify()、 notifyAll()操作的唤醒。
3. 存在被虚假唤醒的可能。
何为虚假唤醒?
虚假唤醒就是一些 obj.wait()会在除了 obj.notify()和 obj.notifyAll()的其他情况被唤醒,而此时是不应该唤醒的。
------------------------------------------------------------
我的理解是, A 被 B 的 notify()唤醒了,但是条件变量不满足了,所以这个虚假指的是条件变量不满足所以虚假
但是原文中却说:“一些 obj.wait()会在除了 obj.notify()和 obj.notifyAll()的其他情况被唤醒”
着我就不懂了,明明 A 是被 B 的 notify()唤醒了啊,什么叫“除了 obj.notify()和 obj.notifyAll()的其他情况被唤醒”?