我粘贴了下面的代码。这已经足够评论了。清除等待()。当它来到这里时,它会跳到另一个街区。那部分我是奥克。我的疑问是为什么我们使用notify和notifyAll()。如果您从下面的代码中删除这两个,它就可以正常工作。
class Reader extends Thread{
Calculator c;
//here we didn't write no-arg constructor. Note this.
// one - arg constructor.
public Reader(Calculator calc){
c = calc;
}
public void run(){
synchronized(c){
// 2. Acquiring the object lock and executes this code of block.
try{
System.out.println("Waiting for calculation...");
c.wait();
// 3. Release the object lock and moves to the second synchronize block below
// 6. Later the object get the lock here and moves on.
}catch(InterruptedException e){
}
System.out.println("Total is: "+c.total);
}
}
public static void main(String[] args){
//Instantiating new with no-arg. One more doubt, How this work without no-arg constructor above. Please explain.
Calculator calculator = new Calculator();
//Instantiating new with one-arg
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
// 1. Once you start here it will goto first synchronized code block above
calculator.start();
}
}
class Calculator extends Thread{
int total;
public void run(){
synchronized(this){
// 4. This block acquires that object lock and executes the code block below.
for(int i=0;i<100;i++){
total +=i;
}
// 5. As per documentation, If we give notify() it will release the object lock to only one thread object of its choice.
// If we use notifyAll(); it will release the object lock to all the three thread object.
notify();
// My doubt here is without using the notify or notifyAll it is working fine.
// As per docs if we use notify() only one object should get the lock. That is also not working here.
}
}
}
一般注释:Object#wait
的javadoc声明
与单参数版本一样,中断和虚假唤醒是可能的,并且应该始终在循环中使用此方法。
因此,等待线程可以在没有通知的情况下唤醒,您的设计应该通过在循环中等待并检查退出条件来考虑这一点(参见javadoc中的示例)。
然而,在您的情况下,问题略有不同。根据Thread#join
javadoc:
当线程终止时,将调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll。
因此,当计算器完成时,它会调用this.notifyAll()
并唤醒所有等待的线程。
如何修复?
您应该使用一个单独的锁对象,类似于计算器中的private final Object lock = new Object();
,并为Readers提供一个getter。
无法保证线程开始运行的顺序。如果Calculator首先运行,则其notify
将丢失,并且不会通知任何读卡器。
这是上面程序的更正版本,它对notify()和notifyAll()有一定的意义。在这里,我实现了Runnable,而不是扩展Threads。这是我唯一的改变。它工作得很好。
class Reader implements Runnable{
Calculator c;
public Reader(Calculator calc){
c = calc;
}
public void run(){
synchronized(c){
try{
System.out.println("Waiting for calculation...");
c.wait();
}catch(InterruptedException e){
}
System.out.println("Total is: "+c.total);
}
}
public static void main(String[] args){
Calculator calculator = new Calculator();
Reader read = new Reader(calculator);
Thread thr = new Thread(read);
Thread thr1 = new Thread(read);
Thread thr2 = new Thread(read);
thr.start();
thr1.start();
thr2.start();
new Thread(calculator).start();
}
}
class Calculator implements Runnable{
int total;
public void run(){
System.out.println("Entered Calculator");
synchronized(this){
for(int i=0;i<20;i++){
total +=i;
}
notifyAll();
}
}
}