notify()方法的调用位置是否重要?(Java)

4
假设我有以下情况:
synchronized void someMethod() {
    ...
    try {
       wait();
    }catch(InterruptedException e) {
       System.out.println("InterruptedException caught");
    } 
    ...
}

并且

synchronized void someOtherMethod() {
    ...
    notify();  
}

线程(Thread)首先访问someMethod,进入wait状态,然后someOtherMethod通知它并返回Runnable状态。在方法中调用notify()的位置是否重要?即使我将notify()调用放置在方法内部的不同位置,行为也没有变化。

当调用notify()时,线程(Thread)应立即得到通知,难道不是吗?

3个回答

5
synchronized 块中调用 notify() 的位置并不重要,因为根据定义,如果你仍然在 synchronized 块内部,那么你仍然持有这个锁。

调用 notify() 时,线程不应立即被唤醒吗?

是的。调用 notify() 会将等待条件的线程(如果有)之一从等待队列移动到阻塞队列(等待锁)。这确实会立即发生,但是唤醒的线程需要获取锁才能开始运行。因此,它立即从等待队列中移出,但仍在等待获取锁。
顺便说一下,我建议将其编写为 this.wait()this.notify(),以明确受影响的对象。

1
调用notify()会将等待队列中的一个线程(如果有)放入阻塞队列。这里不是指Runnable吗?唤醒的线程并没有被阻塞,它只是处于可运行状态,等待被执行。 - Cratylus
唤醒的线程立即被阻塞,等待获取锁。我不认为它在运行队列中。 - Gray
在设计不良的系统中,它可能会以错过唤醒的形式产生影响,例如一个线程执行 if(condition) wait(),而另一个线程执行 makeConditionTrue(); notify(); doSomethingElse(); - selig
我不明白这如何改变我的答案@selig。你能给更多具体信息吗?那里有“同步”部分? - Gray

2
不,notify()调用在synchronized块内的位置并不重要。
我建议使用以下样式:
class SomeClass {
  synchronized void someMethod() throws InterruptedException{
    ...
    while (! someCondition) {
      wait();
    } 
    ...
  }

  synchronized void someOtherMethod() {
    ...
    makeConditionValid();
    notifyAll();  
  }
}

请注意,在wait调用周围使用了while循环。一些JVM可能会发出虚假通知,因此不能保证线程被通知时,导致等待的原始条件仍然有效。此外,唤醒的线程直到通知线程释放锁之前不会运行;因此在等待线程执行条件之前,该条件再次无效是有可能的。


0

这些调用(即Object#waitObject#notify)需要在同步块内进行。由于您的方法是同步的,因此同步块的范围包括方法内的所有内容。因此,它与位置无关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接