Java线程在等待期间无法获取锁是啥状态
Posted
技术标签:
【中文标题】Java线程在等待期间无法获取锁是啥状态【英文标题】:What is the state of Java thread during waiting and unable to obtain lockJava线程在等待期间无法获取锁是什么状态 【发布时间】:2016-04-26 21:23:25 【问题描述】:Java 线程可以被以下任一者持有:
-
无法获得锁。
被 wait() 方法持有。
以上两种场景在Java线程状态方面有什么区别?
考虑以下简单代码:
synchronized(object)
object.wait();
System.out.println("Completed.");
如果两个线程(比如 ThreadA 和 ThreadB)都在 wait() 方法中。例如,当另一个线程调用 notifyAll() 时,ThreadA 将从等待中恢复并获得对象上的锁定并继续。 ThreadB 也将恢复,但无法获得对象上的锁定并被持有,直到 ThreadA 退出同步块。 ThreadB 然后获得锁并继续。
结果将打印两个“已完成”。
在这个例子中,一定有一段时间 ThreadB 从“被 wait() 持有”变为“因为无法获得对象的锁而被持有”。
我想知道它在 Java 内部是如何工作的。请帮忙。
【问题讨论】:
基于enum Thread.State
的Javadoc(我没有尝试过实验),状态应该从WAITING
更改为BLOCKED
。也许你可以做个实验,看看我说的对不对。
这个answer已经非常详细地解释了所有等待线程在收到通知后的行为。
【参考方案1】:
处于object.wait()
状态和等待object
的monitor上锁的区别在于object.wait()
状态的线程释放它所持有的所有object
的monitor,它将与所有的系统中的线程再次重新获取监视器。这使得wait()
成为一个特殊的状态。
因此,在您的情况下,当A
和B
(线程A 和线程B)处于等待状态时,它们没有同步监视器object
,它们都已暂停执行直到某个时间其他线程调用object.notify()
或object.notifyAll()
。当notifyAll()
被调用时,JVM 会唤醒所有处于object.wait()
状态的线程(在本例中为A
和B
),它们会竞争以获取当前synchronized
块的监视器。如果 notify()
被调用,那么 JVM 会随机选择 A 或 B。
这里要注意的是,JVM 没有通知任何特定线程,这就是为什么每个等待线程都必须在 while(notify_condition_for_me)
循环中等待的原因,这会验证等待条件是否已经存在,如果不是则必须进入 @ 987654338@再次状态。
所以正确的代码应该是
synchronized(object)
while(myResourceArrived) //like URL data, JDBC data or something
object.wait();
System.out.println("Completed.");
当A
和B
处于object.wait()
状态时,它们已经释放了之前为object
持有的所有监视器,因此在synchronized
块外等待的任何其他线程将立即能够获取object
的释放监视器进入区块。
【讨论】:
【参考方案2】:查看Thread.State
,更具体地说是WAITING
和BLOCKED
状态。
如果您对内部实现感兴趣,两者都可以使用LockSupport.park()
和LockSupport.unpark(Thread)
来实现,实际上大多数地方都是这样实现的。
附:如果您有兴趣,这里是 Windows (line 4946) 和 Linux (line 5808) 的 OpenJDK park()
实现,这里是 wait()/notify()/notifyAll()
实现(第 1457 行)。他们的评论很好,如果第一眼看起来太复杂,请给它一些时间。
【讨论】:
以上是关于Java线程在等待期间无法获取锁是啥状态的主要内容,如果未能解决你的问题,请参考以下文章