无法获取锁的线程会发生什么情况?
无法获取锁(非自旋)的线程会发生什么情况?它进入 BLOCKED 状态。它如何再次被执行?
Lock lck = new ReentrantLock();
lck.lock()
try
{
}
finally
{
lck.unlock();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
调度程序(或底层的 Lock 实现)负责让它再次运行。如果锁定操作一直被转换为互斥锁调用进入内核,那么调度程序将不会重新调度线程,直到互斥锁变得可用;然后操作系统调度程序将重新唤醒线程。阅读 Context Switch 上的维基百科页面以及其中的链接可能会更深入地了解所涉及的详细机制。也可以直接看
ReentrantLock
不过,这最终会将您的问题归结为一些原语的组合,包括AbstractedQueuedSynchronizer
、各种原子操作,也许还包括LockSupport.park()
和unpark()
。如果您对内核级阻塞/上下文切换特别感兴趣,或者特别对各种 Java 原语(例如,jucLock
或原语对象监视器)是如何在核心。在实践中,由于这是昂贵的,因此可以通过 JVM 或锁实现来优化它。例如,线程实际上可能会旋转一段时间,以查看锁在实际阻塞之前是否已释放。
请注意,Java 线程可能会报告状态 即使底层操作系统线程没有被阻止,特别是在下面的性能白皮书中描述的自适应旋转情况下,也会被阻止。
有一些很棒的资源可以帮助您了解 Java 中的并发控制。领先的万神殿是 Java 并发实践。 Java SE 6 性能白皮书中的 HotSpot 6.0 以及一些相关幻灯片。
The scheduler (or the underlying Lock implementation) is responsible for getting it running again. If the lock action was translated into a mutex call all the way into the kernel, the scheduler will not reschedule the thread until the mutex becomes available; then the OS scheduler will re-awaken the thread. Reading the wikipedia page on Context Switch and links from there might provide more insight into the detailed mechanisms involved. You can also look directly at the code for
ReentrantLock
though that will eventually boil your question down to some combination of primitives includingAbstractedQueuedSynchronizer
, various atomic operations, and maybeLockSupport.park()
andunpark()
. You might augment your question or ask a new one if you're specifically interested in kernel-level blocking/context switches or specifically how various Java primitives (e.g.,j.u.c.Lock
or primitive object monitors) are implemented atop the kernel.In practice, because this is costly, this may be optimized away by the JVM or lock implementation. For instance, the thread may actually spin for a bit to see if the lock is freed before actually blocking.
Note that a Java thread may report the state BLOCKED even if the underlying OS thread is not blocked, specifically in the adaptive spinning cases described in the performance whitepaper below.
There are some great resources out there to learn about concurrency control in Java. Leading the pantheon is Java Concurrency in Practice. Some interesting discussion of synchronization performance in HotSpot 6.0 in the Java SE 6 Performance Whitepaper and some related slides.
锁获取永远不会失败。将其视为尚未成功。
当然,在某些情况下它永远不会成功,但不存在线程被通知失败的转换事件......它只是继续等待。
Lock acquisition never fails. Think of it as having not yet succeeded.
Sure, there are some cases where it will never succeed, but there's no transition event where the thread is notified of a failure… it just keeps waiting.
持有锁的线程解锁锁,然后(或“a”)被阻塞的线程被唤醒。如果持有锁的线程永远不会释放锁(可能是因为它被另一个资源阻塞),那么就会出现死锁。非旋转锁通常会使用 wait()/notify() 原语或类似的东西,以便在锁再次可用时通知线程。
The thread holding the lock unlocks the lock and then the (or "a") blocked thread is woken up. If the thread holding the lock never releases the lock (perhaps because it's blocked on another resource) then you get deadlock. A non-spinning lock will typically use the wait()/notify() primitives or something similar such that the thread is notified when the lock again becomes available.