【问题标题】:Signalling threads in a lock's condition发信号通知处于锁状态的线程
【发布时间】:2013-07-22 17:22:43
【问题描述】:

我从这个API 中获得了以下几点,我想知道以下两点之间的区别:

  1. 等待线程按 FIFO 顺序发出信号。

  2. 从返回的线程重新获取锁的顺序 等待方法与最初获取的线程相同 锁,默认情况下不指定,但用于公平锁 有利于那些等待时间最长的线程。

它与Condition类有关,通常由ReentrantLock方法.newCondition()返回,我引用它的部分解释了Condition的方法与Object类的常规监控方法之间的区别。

“等待线程以 FIFO 顺序发出信号”。我认为只要 lock 被创建是否公平,等待线程以 FIFO 顺序发出信号的事实是完全无关的,不是吗?因为无论如何,它们是否已构建,公平与否,决定了它们如何排队。

只是要求确认。

提前致谢。

【问题讨论】:

    标签: java concurrency locking reentrantlock


    【解决方案1】:

    我认为源代码可以为我们提供更多关于它如何工作的线索。ReentrantLock.newCondition()AbstractQueuedSynchronizer 中返回一个 ConditionObject。这里是源代码链接AQS source code

    1.等待线程以先进先出的顺序发出信号。

    AbstractQueuedSynchronizer中有两个队列。

    一个是等待锁(就叫它锁等待队列),你会看到两个volatile变量headtailAbstractQueuedSynchronizer的类定义,fairness参数会影响这个队列的行为。当你新建一个fairReentrantLock并调用acquire时,AQS会调用FairSynctryAcquire 来检查当前线程是否是锁等待队列中等待的第一个线程,请参阅 hasQueuedPredecessors

    另外一个队列是ConditionObject定义中的信号队列,你会看到两个变量firstWaiterlastWaiter。当await 被调用,一个节点将添加到队列的尾部,当 signal 被调用时,头部的一个节点将被出列并添加到锁等待队列以重新获取锁。加入锁等待队列并不意味着它会被唤醒,而是会在signal之后调用一个Lock.unlock(),唤醒等待者,请参阅unparkSuccessor

    2.从等待方法返回的线程重新获取锁的顺序与最初获取锁的线程相同,默认情况下未指定,但公平锁优先考虑等待时间最长的线程。

    await方法中唤醒并不是持有锁的意思,它会调用acquireQueued重新获取锁,可以再次被停住。 在我的理解中,最初获取锁的顺序和调用await的顺序一样,所以和调用acquireQueued的顺序一样,让我困惑的是但是对于公平锁来说,有利于那些等待时间最长的线程。,当从 await 唤醒时,在我看来,它将是锁等待队列中的第一个线程,当调用acquireQueued并检查p == head && tryAcquire(arg)时,锁是否公平无效。

    希望这会有所帮助,如果我错了,请告诉我。

    【讨论】:

      【解决方案2】:

      只要创建一个锁是公平的还是不公平的,等待线程按 FIFO 顺序发出信号的事实是完全不相关的,不是吗?因为无论如何,它们是否已被构建,公平与否,决定了它们如何排队。

      我认为这是相关的。

      假设 T1 和 T2 在条件 C 上等待(T1 等待的时间比 T2 长),T3 在监视器内运行,而 T4 正在等待其初始锁获取。 T3 向 C 发出信号并让监视器释放锁定。假设没有虚假唤醒发生。

      如果锁公平,T4肯定会在T1之前获得锁,但是等待线程按FIFO顺序发出信号这一事实可以保证T1会在T2之前获得锁。 p>

      另外,如果锁不公平,我们不能说 T1 和 T4 之间哪个线程首先获得锁,但是等待线程以 FIFO 顺序发出信号这一事实再次保证了T1 将在 T2 之前获得锁,前提是在 T1 获得锁之前没有其他信号发生(例如,如果 T1 负责下一个信号)。

      【讨论】:

        【解决方案3】:

        请查看以下问题的答案:

        1.等待线程以先进先出的顺序发出信号。

        当我们调用Condition的await()方法时,线程进入等待状态,上面的语句是指这些处于等待状态的线程是如何发出信号的。因此,如果线程 T1 在 T2 之前进入等待状态,则 T1 将在 T2 之前发出信号。

        2.从等待方法返回的线程重新获取锁的顺序与最初获取锁的线程相同,默认情况下未指定,但公平锁优先考虑等待时间最长的线程。

        继续上面的语句,当等待线程发出信号时,它往往会重新获取锁。虽然上面说的是 T1 会在 T2 之前发出信号,但是在重新获取锁时,重新获取的顺序使用了 Lock 定义的概念。因此,这取决于 Lock 对象的创建方式。在创建 Lock 时,您可能已经指定了一个公平参数:

        ReentrantLock(boolean fair)

        如果是,则使用该参数,如果不是,则发生锁的默认行为,您可以在 link 阅读更多关于 ReentrantLock 锁的信息

        这些陈述可能有更多解释,只是试图在这里最好地详细说明我的理解。希望能够澄清。

        干杯!!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多