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() 成为一个特殊的状态。

因此,在您的情况下,当AB(线程A 和线程B)处于等待状态时,它们没有同步监视器object,它们都已暂停执行直到某个时间其他线程调用object.notify()object.notifyAll()。当notifyAll() 被调用时,JVM 会唤醒所有处于object.wait() 状态的线程(在本例中为AB),它们会竞争以获取当前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.");

AB 处于object.wait() 状态时,它们已经释放了之前为object 持有的所有监视器,因此在synchronized 块外等待的任何其他线程将立即能够获取object的释放监视器进入区块。

【讨论】:

【参考方案2】:

查看Thread.State,更具体地说是WAITINGBLOCKED 状态。

如果您对内部实现感兴趣,两者都可以使用LockSupport.park()LockSupport.unpark(Thread) 来实现,实际上大多数地方都是这样实现的。

附:如果您有兴趣,这里是 Windows (line 4946) 和 Linux (line 5808) 的 OpenJDK park() 实现,这里是 wait()/notify()/notifyAll() 实现(第 1457 行)。他们的评论很好,如果第一眼看起来太复杂,请给它一些时间。

【讨论】:

以上是关于Java线程在等待期间无法获取锁是啥状态的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程系列--“JUC锁”05之 非公平锁

面试JAVA基础锁

Java入门教程!java开发经常出差

北大青鸟java半年学费,Java核心知识点

在阿里工作5年了,java教程百度网盘下载

不看绝对血亏!java开发视频教学