来自ReentrantLock javadoc:
合理模式
当构建为公平时,线程使用 大致 争夺进入权 到货订单政策。当前举行 锁是释放最长等待的单个写作线程 被分配写锁,或者如果有一组读者线程 等待所有等待的编写器线程,该组将是 分配了读锁定。试图获得公平阅读的线程 如果保持写锁定,则锁定(非重复)将阻塞 有一个等待的作家线程。线程不会获取读取 锁定,直到最旧的当前正在等待的编写器线程 获取并释放写锁。当然,如果是一个等待作家 放弃等待,留下一个或多个读者线程最长 队列中的服务员用写锁定免费,然后那些读者会 被赋予读锁定。
尝试获取公平写锁定的线程(非重复) 除非读锁定和写锁定都是空闲的(否则将阻塞) 意味着没有等待的线程)。 (注意非阻塞 ReentrantReadWriteLock.ReadLock.tryLock()和 ReentrantReadWriteLock.WriteLock.tryLock()方法不承认这一点 公平的设置,如果可能的话,将获得锁定,无论如何 等待线程。)
也许这是我的英语问题,但我看到这个解释的矛盾:
从第一次paragrapgh我不明白约到货订单政策的含义
请澄清这一矛盾。
答案 0 :(得分:3)
在这里,引用你的引用:
或者如果有组的读者线程
换句话说:作家胜过单读者;但是当一群读者想要锁定时,那些人会获得锁定。
关于问题:" group 实际意味着" ......这将是一个实施细节,只有通过查看source code才能获得。
答案 1 :(得分:3)
我没有看到你所引用的描述中的任何矛盾,我认为你正确地理解#1但错误地理解#2。
顺便说一下,我认为GhostCat的描述是错误的。没有什么能够总结不同线程的等待时间并对它们进行比较。逻辑实际上要简单得多。
我的回答往往很长,但有希望解释。
非公平模式
让我们从" nonfair"开始先锁定模式。 "非公平"这意味着
持续争用的非公平锁可能无限期推迟一个或多个读写器线程
所以"公平"这意味着没有线程可以永远等待。 " Nonfairness"意味着如果有一个恒定的线程流来获取读锁定,并且我们有一些等待写锁定的线程(W1
),那么当读取锁定的新线程(Rn
)到来时它可能会在W1
线程之前锁定,因此可能在不幸的情况下无限期地发生。请注意,即使在" nonfair"模式ReentrantReadWriteLock
尝试是合理公平的,它不是保证公平,因为正如文档所说,"公平"不是免费的,而且成本较低。
非公平模式示例
那么真正的不公平行为可能会如何发生。假设有一个W0
线程持有写锁,而现在的队列是R0
和R1
等待读锁,然后W1
等待写锁,还有将来会有大量的新线程来读取锁Ri
。还假设线程R1
线程在系统中具有最低优先级,并且OS永远不会突破线程的优先级,即使它们还没有工作很长时间。
W0
保留,等待队列为[R0
,R1
,W1
] W0
释放写锁定,R0
被唤醒并获取读锁定,现在R1
具有低优先级且未被唤醒,因此无法获取读取现在锁定。等待队列现在是[R1
,W1
] W1
被唤醒但由于R0
R0
仍然保持读锁定,新读者线程R2
到来。由于已经获取了读锁定,并且等待队列中的第一个线程是读取器R1
,R2
立即获取读锁定。读锁定由[R0
,R2
]保存。等待队列仍然是[R1
,W1
]。R0
释放了锁定,但W1
仍然无法获得写锁定,因为它现在由R2
保留。等待队列仍然是[R1
,W1
]。R2
仍然保持读取锁定,新读者线程R3
到达,获取读锁定,同样的故事继续发生。重要的是:
W1
被读取线程R1
阻止读取,由于低优先级和/或纯粹的运气不好而未被唤醒以获取锁定。Ri
线程,找出整个队列中是否有任何写线程需要花费一些时间和精力,因此应用了更简单的启发式(步骤#4):第一个等待线程是否是写入或读取线程,R1
正在读取允许快速获取的线程。还要注意,步骤#4中的这个逻辑检查队列中的第一个线程是我前面提到过的公平尝试,这比没有这种检查的天真实现更好。 合理模式
现在回到公平。正如您在sources of FairSync内部类中所发现的那样(我剥离了细微的细节):
class FairSync extends Sync {
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
字面意思是,"公平"和"非公平的"这是"公平"模式读取器线程在获取读取锁之前,否则可以在不破坏ReadWriteLock合约的情况下获取它,另外检查队列中是否还有其他线程。这样,来自前一个示例的W1
线程不能永远等待R2
,并且下一个线程不会在它之前获取读锁定。
合理模式示例
在公平模式中对同一示例的另一次尝试:
W0
保留,等待队列为[R0
,R1
,W1
] W0
释放写锁定,R0
获取读锁定队列[R1
,W1
] W1
被唤醒但由于R0
R2
到达队列。尽管读取锁定由R0
保持,而R2
似乎也能够获取它,但它并不会这样做,因为它会先看到W1
。读取锁定由R0
保留,队列为[R1
,W1
,R2
] W1
和R2
无法获取锁定,直到R1
从队列中删除。因此,最终R1
被唤醒,锁定进行处理并释放锁定。W1
获取了写锁定R2
,R3
,其他人仍然在等待队列。就此示例而言,R0
和R1
形成"组"但是R2
并不属于那个" group"因为它在队列中的W1
之后。
摘要
所以第一段描述的是当释放锁并且策略很简单时会发生什么:第一个等待的线程获取锁。如果第一个等待线程恰好是读线程,则第一个写入线程在 之前队列中的所有其他读线程 获取读锁定。所有这些读取线程都被称为" group"。请注意,这并不意味着所有读取线程都在等待锁定!
第二段描述了当新的读取线程到达并尝试获取锁定时发生的情况,此处的行为实际上与第一段一致:如果在当前线程之前队列中存在等待的写入线程,则不会获取如果在释放锁定之前将锁定添加到队列并且第1段中的规则适用,则锁定方式与获取锁定的方式相同。 希望这会有所帮助。
答案 2 :(得分:2)
公平模式政策只是"大约到达顺序"因为等待获取读锁定的线程被批处理,并且稍后到达获取读锁定的线程可能比同一批次中由于OS调度而尝试获取读锁定的另一个线程获得锁定。
A"阅读器线程组"可以只是一个线程。
规范中没有矛盾,但可能没有那么明确。
假设线程A在互斥锁上持有写锁定。
线程B到达并尝试获取写锁定。 然后线程C到达并尝试获取读锁定。然后线程D到达并尝试获取读锁定。然后线程E到达并尝试获得写锁定。然后线程F到达并尝试获取读锁定。
现在,线程A解锁了互斥锁。公平模式策略意味着线程B将获得锁定:它一直在等待最长时间。
当线程B释放锁定时,线程C和D将获得读取锁定,但不会获得线程F.C和D是一组读取器线程,等待的时间超过所有等待的写入器线程"。线程F仍然被阻塞,因为它比编写线程的线程E等待的时间更短。
如果线程E然后放弃等待(例如它超时),则线程F现在是最旧的等待线程,并且当前锁定是读锁定,因此线程F可以在线程C和D释放它们之前获取锁定
如果线程G现在尝试获取写锁定,它将阻塞,直到所有线程C,D和F都释放了它们的读锁定。
如果线程H现在尝试获取读锁定,它将阻止:有一个等待的写入程序线程。
如果线程I现在尝试获取一个写入器锁,它将阻塞:有一个等待线程的队列。
现在,C,D和F释放它们的锁,因此线程G(最长的等待线程)获取写入器锁。
线程G释放锁,线程H获取锁:它是一个读取器线程的组,其等待的时间比任何等待的编写器都长。
最后,当线程H释放锁时,线程我可以获取它。