【问题标题】:How do Conditions in Java know which Thread to trigger?Java 中的条件如何知道要触发哪个线程?
【发布时间】:2019-02-11 07:34:55
【问题描述】:

我正在阅读来自 Java 的Condition Documentation,但我有一个误解。阅读他们的puttake 示例,正如您在函数put 代码行中看到的那样:notEmpty.signal() 其中notEmpty 是来自lock 的条件。

我想知道如果有多个线程正在等待notEmpty 的信号怎么办。在这种情况下会发生什么以及触发了哪个线程?

【问题讨论】:

    标签: java multithreading concurrency operating-system


    【解决方案1】:

    我想知道的是,如果有多个线程在等待 notEmpty 的信号怎么办。这种情况下会发生什么,触发了哪个线程?

    其他人已经回答了,不知道会触发哪个线程。

    所以我猜这种方法总共只适用于两个线程?

    取决于“这种方法”的含义。让多个线程等待相同的条件通常确实有意义。诀窍是,由于您无法知道哪个线程会被唤醒,因此您应该以这样一种方式编写代码,即重要哪个线程被唤醒。

    这是编写多线程代码时应尝试遵循的良好实践示例,即:当有工作要完成时,哪个线程完成工作并不重要。

    【讨论】:

    • 不能同意更多:)
    【解决方案2】:

    我觉得线程先调用await()会先被触发,结论来自source code

    await() 做了什么?

    1. 创建一个等待节点并将该节点添加到由条件维护的fifo队列中
    2. 释放锁,你看到在调用await()之前,你需要调用lock.lock()
    3. 测试 signal() 是否在步骤 2 中被其他线程调用。如果不是,则停止当前线程。

    signal() 做了什么?

    • Condition维护的队列中取一个节点,放到Lock维护的队列中,所以如果有一个线程调用await() 首先,它会先进入Lock的队列

    停放的线程什么时候被唤醒?

    显然Lock.unlock()会在Condition.signal()之后被调用,Lock.unlock()会得到一个节点在Lock的等待队列中从头到尾,见AbstractQueuedSynchronizer#unparkSuccessor,所以如果你先进入Lock的队列,你会先被触发.

    【讨论】:

      【解决方案3】:

      它对处理它的操作系统进行系统调用。 JVM 不知道哪个线程会唤醒。

      线程由操作系统而不是 JVM 管理,因此它所能做的最好的事情就是进行正确的系统调用,让操作系统完成其余的工作。

      【讨论】:

      • 所以在一个真正的实现中,如果我们有这个带有signalawait的代码,那么signal会触发哪些线程是一个废话,所以我猜这种方法只适用总共两个线程?谢谢
      • @BrijendarBakchodia 除非您使用更昂贵的“公平”锁,否则顺序是随机的,注意await 可以虚假唤醒。
      • 好的,还有一个问题。从该文档代码示例中,假设线程Produce 调用put,因此Produce 现在拥有锁lock。但while 条件为真,因此 Produce 执行notFull.await()。我现在的问题是,如果线程Consume 调用,在lock.lock() 的行上究竟会发生什么?我有点困惑,因为我们让旧锁进入临界区,现在需要从不同的线程获取它。
      • @BrijendarBakchodia 不确定您的意思,但调用 await 会释放锁,直到它唤醒并重新获取它。
      • 我有一个疑问——一旦我打电话给cond.await() 并且有人打电话给cond.signal(),那么这个cond.await() 会明白然后它返回return 然后再次检查条件while 循环。我想知道的是,这个await() 只有在我重新获得lock 之后才会返回,对吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      相关资源
      最近更新 更多