6

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

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

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

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

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

只是要求确认。

提前致谢。

4

3 回答 3

1

请参阅以下对您的问题的回答:

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

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

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

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

ReentrantLock(boolean fair)

如果是,则使用该参数,如果不是,则发生锁定的默认行为,您可以在此链接上阅读有关 ReentrantLock Locks 的更多信息

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

干杯!!

于 2013-07-23T21:14:40.450 回答
0

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

我认为这是相关的。

考虑一个场景,其中 T1 和 T2 正在等待条件 C(T1 等待的时间比 T2 长),T3 在监视器内运行,而 T4 正在等待其初始锁获取。T3 向 C 发出信号,然后让监视器释放锁定。让我们假设没有发生虚假唤醒

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

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

于 2014-01-16T15:23:16.937 回答
0

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

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

AbstractQueuedSynchronizer中有两个队列。

一个是等待锁(就叫它锁等待队列),你会在 AbstractQueuedSynchronizer的类定义中看到两个 volatile 变量,公平参数会影响这个队列的行为。当你新建一个公平的ReentrantLock并调用获取时,AQS 会调用FairSynctryAcquire来检查当前线程是否是锁等待队列中等待的第一个线程,参见hasQueuedPredecessors

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

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

从await方法中唤醒并不意味着持有锁,它会调用acquireQueued重新获取锁并可以再次停放。在我的理解中,最初获取锁的顺序与调用await的顺序相同,因此与调用acquireQueued的顺序相同,但让我感到困惑的是,公平锁偏爱那些等待时间最长的线程。,当从await中唤醒时,在我看来,它将是锁等待队列中的第一个线程,当调用acquireQueued并检查p == head && tryAcquire(arg)时,锁是否公平没有影响。

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

于 2017-08-22T11:07:04.563 回答