notifyAll是否在不检查条件的情况下从循环中删除等待?

时间:2019-01-08 00:09:10

标签: java multithreading wait synchronized notify

public class ShareResource {

private int n = 0;

public synchronized void p() throws InterruptedException {
    while (n > 0) {
    wait();
    }
    n++;
}

public synchronized void r() {
  n = 0;
  notifyAll();
}

}

如果我使用此资源启动了两个线程,并且它们都在wait()处,并且我在资源中调用了方法r(),这会唤醒两个线程而不检查条件吗? 是否会在两个线程中读取代码直到方法结束?在“相同”时间?

2 个答案:

答案 0 :(得分:1)

  

是否将在两个线程中读取代码直到方法结束?在同一时间?

不,不。 notifyAll()的工作方式是每个对象最终都从wait()醒来后才执行它们的代码。但是,一次只能执行一个线程。因此,一个线程通过调用r()退出循环后,它会增加计数器的数量,因此不会释放另一个线程。因此,只有一个线程执行到最后-不在两个线程中执行。

  

如果我使用此资源启动了两个线程,并且它们都在wait()处,并且我在资源中调用了方法r(),这会唤醒两个线程而不检查条件吗?

我假设您的意思是当您表示“不检查条件”时退出while循环。如上所述,两个线程都不是这种情况。

TL; DR:notifyAll()一次只允许一个线程执行,但是所有这些线程最终都将最终执行。

来源:https://stackoverflow.com/a/37046/10869762

答案 1 :(得分:1)

两个等待线程都收到通知。两个等待线程都在循环内唤醒。两者都必须检查条件才能退出循环。但是,其中一个等待线程将首先进入,然后将另一线程关上。

当等待线程被通知时,它仍处于wait方法中,直到获得锁,它才能离开wait方法。 (请记住,等待是在同步方法内部,并且线程在等待开始时就放弃了对ShareResource对象的锁定。)当然,一次只有一个线程可以获取该锁定。

在两个通知线程中,第一个获得锁的线程将离开wait方法,然后检查循环条件。它发现n为0,可以退出循环。然后线程递增n。所有这些都是在持有锁的情况下发生的,因此没有其他线程可以干涉。

一直以来,第二个线程已被阻塞;它被与第一个线程相同的通知唤醒,但是无法获取锁定。一旦第一个线程退出了p方法并释放了锁,第二个线程就可以获取该锁并退出wait方法。此时,它检查while循环条件,由于第一个线程,发现n大于0,然后再次输入wait方法,并返回到它开始的地方。

请注意,notifyAll通常很浪费,因为唤醒了多个线程,但是只有一个线程可以取得进展。