我有一个简单的程序,我觉得很困惑。代码段如下:
class Processor{
public void produce() Throws InterruptedException{
synchronized(this){
System.out.println("Producer Running...");
wait();
System.out.println("Resumed");
}
}
public void consume() Throws InterruptedException{
synchronized(this){
Thread.Sleep(2000);
System.out.println("Consumer Running... Press return key to return");
scan.nextLine();
notify();
Thread.sleep(5000);
}
}
现在我的问题是,当我们在“produce”方法中调用wait()时,执行会立即转移到“consume”方法。 (生成和使用在不同的线程中执行)。但是当notify();在“消耗”方法中调用,执行不会立即转移。它等待Thread.sleep(5000)完成。为什么会这样呢?
答案 0 :(得分:3)
嗯,原因很简单。
当一个线程在某个对象上调用wait()
时,它进入等待状态并停止执行(它从调度中删除)。当等待一个线程释放它已经采取的所有监视器(并且它需要在唤醒后重新获得它们)
当一个线程在某个对象上调用notify()
时,它会唤醒另一个等待它的线程,但它本身不会进入等待状态,因此它会继续运行。
在生产者线程调用之后,通知它继续运行并执行五秒睡眠。睡眠时,线程会保留它所采用的所有监视器(您位于同步(此)块内,因此您有一个监视器,用于"这个"对象)。调度程序无法运行刚刚通知的消费者线程,因为它需要在恢复之前重新读取监视器,并且在生产者线程停止休眠并退出同步块之前它不会被释放
答案 1 :(得分:2)
虽然您似乎缺少一些我需要完全准确解释的代码,但即使我的猜测不正确,我也会尽力提供适用的解释。
wait()
和notify()
是在互斥对象上调用的方法 - 在本例中为this
。
wait()
导致当前正在执行的线程暂停并放弃该互斥锁(我认为它只是调用wait()
的互斥锁,可能是所有这些。不确定),之后另一个线程可以获取互斥锁并开始执行。这就是您在执行wait()
时观察到控制权立即转移的原因。
在互斥锁上调用notify()
时,等待该互斥锁的线程会唤醒并尝试获取锁定。但是,在锁定可用之前不能这样做 - 在这种情况下,直到锁定(this
)被调用notify()
(消费者线程)的线程释放。只有当使用者线程从synchronized
块退出时,才会释放互斥锁,该块位于代码中的Thread.sleep(5000);
调用之后。 sleep()
不释放当前线程已获取的任何互斥锁,因此第一个线程必须等到第二个线程完成休眠并退出synchronized
块。
这就是wait()
立即转移控制的原因,而notify()
(在这种情况下)当前正在执行的线程在先前等待的线程可以继续执行之前完成其方法。
答案 2 :(得分:0)
假设您使用差异线程中的相同对象调用这两个方法。
如果您不想等待5000毫秒,请使用wait(5000)而不是Thread.sleep(5000)。
notify方法,取一个(随机)先前等待的线程,等待获取运行/当前线程之前已经采用的(对象的)锁定,并在当前线程释放后立即将其标记为恢复锁。
在这种情况下,它将释放锁定并很快完成Thread.sleep(5000)并离开同步块。
请注意,如果您使用不同的对象调用生产或消费,则事情会完全不同。我强烈建议您阅读this文章。
希望它有所帮助!正如下面的好答案!
答案 3 :(得分:0)
原因是Thread.sleep(5000L)在对象监视器等待时没有释放锁定,这与等待(5000L)相反。这在Thread.sleep()的Javadoc中指定:
......线程不会失去任何监视器的所有权。
Object.wait()的javadoc指定:
...此方法导致当前线程(称为T)放置自身 在此对象的等待集中,然后放弃任何和所有 对此对象的同步声明...