与构造不同,ReentrantLock是非结构化的 - 即您不需要使用块结构进行锁定,甚至可以跨方法持有锁定。例如:synchronized
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
这种流不可能通过构造中的单个监视器来表示。synchronized
除此之外,还支持支持超时的锁定轮询和可中断锁定等待。 还支持可配置的公平性策略,允许更灵活的线程调度。ReentrantLock
ReentrantLock
此类的构造函数接受可选的公平性参数。当设置为 ,在争用下时,锁有利于授予对等待时间最长的线程的访问权限。否则,此锁不保证任何特定的访问顺序。与使用默认设置的程序相比,使用公平锁(由许多线程访问)的程序可能显示较低的总体吞吐量(即,速度较慢;通常慢得多),但获得锁和保证没有饥饿的时间差异较小。但请注意,锁的公平性并不能保证线程调度的公平性。因此,使用公平锁的众多线程之一可能会连续多次获得它,而其他活动线程没有前进并且当前未持有该锁。另请注意,不定时方法不遵循公平性设置。如果锁定可用,即使其他线程正在等待,它也会成功。true
tryLock
ReentrantLock
也可能更具可扩展性,在更高的争用下表现更好。您可以在此处阅读有关此内容的更多信息。
然而,这一说法受到质疑。请参阅以下注释:
在重入锁定测试中,每次都会创建一个新锁定,因此没有独占锁定,并且生成的数据无效。此外,IBM 链接没有为底层基准测试提供源代码,因此无法确定测试是否正确执行。
什么时候应该使用 s?根据那篇开发者文章...ReentrantLock
答案很简单 - 当你实际需要它提供的东西时使用它,比如定时锁定等待,可中断锁定等待,非块结构锁定,多个条件变量或锁定轮询。 还具有可伸缩性优势,如果您实际遇到表现出高争用的情况,则应使用它,但请记住,绝大多数块几乎从未表现出任何争用,更不用说高争用了。我建议使用同步进行开发,直到同步被证明是不充分的,而不是简单地假设如果使用.of,则“性能会更好”。请记住,这些是高级用户的高级工具。(真正的高级用户往往更喜欢他们能找到的最简单的工具,直到他们确信这些简单的工具是不够的。与往常一样,首先要正确,然后担心您是否必须使其更快。synchronized
ReentrantLock
synchronized
ReentrantLock
在不久的将来将变得更加相关的最后一个方面与Java 15和Project Loom有关。在虚拟线程的(新)世界中,底层调度程序将能够比它能够更好地工作,这至少在最初的Java 15版本中是正确的,但以后可能会进行优化。ReentrantLock
synchronized
在当前的 Loom 实现中,可以在两种情况下固定虚拟线程:当堆栈上有本机帧时 ( 当 Java 代码调用本机代码 (JNI) 然后回调到 Java 时 — 以及当在块或方法中时。在这些情况下,阻塞虚拟线程将阻塞承载它的物理线程。一旦本机调用完成或监视器被释放(块/方法被退出),线程就会被取消固定。synchronized
synchronized
如果您有一个由 保护的常见 I/O 操作,请将监视器替换为 ,以便您的应用程序在修复监视器固定之前(或者,如果可以的话,使用更高的性能),就可以让您的应用程序完全受益于 Loom 的可伸缩性提升。synchronized
ReentrantLock
StampedLock