到底 java 虚假唤醒是怎么回事? 网上都没有一个好的例子啊
1
kaneg 2017-03-01 19:47:23 +08:00 via iPhone
你到底在说啥?请用专业术语
|
2
snnn 2017-03-01 20:05:23 +08:00 via Android
听不懂
|
3
rogerchen 2017-03-01 21:33:49 +08:00
|
4
esolve OP @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()的其他情况被唤醒”? |
5
choury 2017-03-02 00:33:36 +08:00
我一般会在 wait 外面套 while ,而不是 if
|
6
linbiaye 2017-03-02 07:32:20 +08:00
Linux man 手册
"Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return." Oracle 文档: http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait%28%29 "As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop: synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition } " poxis 的 pthread_cond_wait 就是有 suspicious wakeup ,你要问为什么会有,我只能说无可奉告。你唯一要做的就是在循环里面检测 condition 。 |