Java 虚假唤醒怎么网上都没有一个好的例子? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
esolve
V2EX    Java

Java 虚假唤醒怎么网上都没有一个好的例子?

  •  
  •   esolve 2017-03-01 19:45:53 +08:00 3770 次点击
    这是一个创建于 3221 天前的主题,其中的信息可能已经有所发展或是发生改变。

    到底 java 虚假唤醒是怎么回事? 网上都没有一个好的例子啊

    7 条回复    2017-03-02 15:05:41 +08:00
    kaneg
        1
    kaneg  
       2017-03-01 19:47:23 +08:00 via iPhone
    你到底在说啥?请用专业术语
    snnn
        2
    snnn  
       2017-03-01 20:05:23 +08:00 via Android
    听不懂
    rogerchen
        3
    rogerchen  
       2017-03-01 21:33:49 +08:00
    @kaneg
    @snnn
    说的是 Spurious wakeup

    @esolve
    就是 cv 返回了也不一定可以拿 mutex ,还是要检测。这是多线程编程基础,跟语言关系不大, java 例子那本 java concurrency 上就有。
    esolve
        4
    esolve  
    OP
       2017-03-02 00:02:26 +08:00
    @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()的其他情况被唤醒”?
    choury
        5
    choury  
       2017-03-02 00:33:36 +08:00
    我一般会在 wait 外面套 while ,而不是 if
    linbiaye
        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 。
    domty
        7
    domty  
       2017-03-02 15:05:41 +08:00
    @esolve #4
    只有我认为他在状况里的内容写错了吗?

    "4. A 线程调用 notify(),唤醒等待中的线程 A 。"
    应该是 "A 线程调用 notify(),唤醒等待中的线程 B "

    "6. 然后, A 获取到竞争锁, A 中调用 list.remove(list.size() - 1),则会报数据越界 exception 。"
    应该是"6. 然后, B 获取到竞争锁, B 中调用 list.remove(list.size() - 1),则会报数据越界 exception 。"

    才对吧?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4570 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 03:58 PVG 11:58 LAX 19:58 JFK 22:58
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86