【问题标题】:How does wait() get the Lock back in JavaJava中wait()是如何取回锁的
【发布时间】:2013-05-26 15:04:05
【问题描述】:

这是一种提倡的范式,应该在同步块内的 while 循环内调用 wait()。

我的问题是 waiting() 线程是如何取回锁的?

// Thread 1
    synchronized (mon) {
     while (!condition) 
          mon.wait();

    // Do something
    }

//Thread 2
    synchronized (mon) {//set condition appropriately
            mon.notify();
    }

考虑线程 1 首先运行并开始等待条件。它释放锁,线程 2 获得锁设置条件并通知线程 1。现在线程 1 获得锁,检查条件并开始执行“做某事”。

我的问题是,当线程 1 被通知它从 while 条件开始执行时,具有 Synchronized(mon) 的代码行将不再执行,那么线程 1 如何获取锁?将锁返回给线程 1 的内部动态是什么?

【问题讨论】:

    标签: java multithreading synchronization locking wait


    【解决方案1】:

    当 Thread1 收到通知时,线程必须获得锁才能退出等待方法,请参阅 Object#wait 的 java 文档:

    线程T 然后从等待集中移除 对象并重新启用线程调度。然后它在 通常的方式是与其他线程进行权限同步 目的;一旦它获得了对物体的控制权,它的所有 对象上的同步声明恢复到现状 ante - 也就是说,截至wait 方法被调用。线程T 然后从 调用wait 方法。因此,在从 wait方法,对象和线程的同步状态 T 与使用 wait 方法时完全相同 调用。

    【讨论】:

    • @Nathan :我想我们知道答案 :-) 我们不(至少我不明白)Java Doc 的这一部分:因此,从 * {@code 返回wait} 方法,对象和 * 线程 {@code T} 的同步状态与调用 {@code wait} 方法 * 时完全相同。
    • @Geek:你不明白什么?退出等待方法会将线程置于同步块中,因此需要先获取锁。否则它将在没有获得锁的情况下在同步块中执行代码。
    • @NathanHughes :我知道它从与调用 wait() 调用时相同的状态开始。是不是说从wait()函数内部释放了锁,wait()函数直到函数中最后一行代码才执行,然后通知后重新获取锁,然后等待() 完成,代码开始从应用程序代码运行?
    • @Geek:是的,一旦等待的对象再次获得锁,等待就结束了。
    【解决方案2】:

    synchronized(mon) 不是必须执行的表达式。

    它是源代码中的一个语法元素,它告诉编译器(然后是运行时)代码的包装部分只能在当前线程获得与mon 关联的锁之后执行,即使您不会“来自”同步块之前的代码行。

    wait() 释放锁,在返回之前必须重新获得它。

    【讨论】:

    • 你的答案是绝对正确的。你能告诉我这个元数据信息在运行时是如何工作的吗?能否请您指出一些我可以阅读的资源。
    • 我猜你可以在JVM specifications 中找到你想要的东西,但我从来没有读过它们。
    • 调用wait通知JVM获取锁的线程想要放弃它。它的 JVM 将线程放入等待队列并释放锁。当 notify(all) 被调用时,信号被发送到 JVM,获取锁的线程(其 notify(all) 已被调用)已释放锁,并且任何符合条件的候选人(在 JVM 放置的等待队列中) ) 是 JVM 选择来获取锁的。看这个链接了解控制流booxs.biz/images/java/thread-states.png
    • @saury:确切地说,通知线程在调用 notify() 时不会释放锁。它只有在退出同步块时才会被释放。
    • @JBNizet 拼图的关键部分。谢谢解释。
    【解决方案3】:

    Thread 1 收到通知后,立即获得锁并开始运行//做某事

    Thread 1 等待时只是暂时释放锁,当线程收到通知时,它可以再次获得锁,无需运行 synchronized(...)。

    【讨论】:

      【解决方案4】:
      // Thread 1
       synchronized (mon) {
       Systemout.println("I am invoked!");
       while (!condition) 
            mon.wait();
      
      // Do something
      }
      
      //Thread 2
      synchronized (mon) {//set condition appropriately
              mon.notify();
      }
      

      在原始场景中: 考虑线程 1 首先运行并开始等待条件。它释放锁,线程 2 获得锁设置条件并通知线程 1。现在线程 1 获得锁,检查条件并开始执行“做某事”。

      如果我正确理解以下内容:

      线程 T 然后从该对象的等待集中移除并重新启用线程调度。然后它以通常的方式与其他线程竞争对象同步的权利;一旦它获得了对象的控制权,它对对象的所有同步声明都将恢复到之前的状态——即,恢复到调用等待方法时的状态。线程 T 然后从调用等待方法返回。因此,从等待方法返回时,对象和线程 T 的同步状态与调用等待方法时完全相同。

      线 Systemout.println("我被调用了!"); 不会被执行,因为“因此,从等待方法返回时,对象和线程 T 的同步状态与调用等待方法时完全相同。”

      我说的对吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-02-11
        • 1970-01-01
        • 2013-06-19
        • 2016-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多