为啥在我的 java 代码中没有调用通知
Posted
技术标签:
【中文标题】为啥在我的 java 代码中没有调用通知【英文标题】:why is notify not getting called in my java code为什么在我的 java 代码中没有调用通知 【发布时间】:2015-02-27 09:14:33 【问题描述】:这是我的代码:
public class ProducerConsumer
public static void main(String[] args)
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt= new ProducerT(p); // with p obj i am creating thread
ConsumerT ct=new ConsumerT(p); // with same p obj i am creating thread
pt.start();
ct.start(); //i am starting 2 threads
class ProduceCosumeData
boolean flag;
public synchronized void printStringP(int n)
for(int i=0;i<n;i++)
try
if(flag) //for frist time flag is flase so, wait will skip
wait();
else
flag=true; //for next time onwards wait() will get call
System.out.print("Pay");
notify();//after this why my wait() not canceling in inprintStringC()
catch(Exception e)
System.out.print(e);
public synchronized void printStringC(int n)
for(int i=0;i<n;i++)
try
wait(); // why it is not out of this after notify()
System.out.print("Tm");
notify();
catch(Exception e)
System.out.print(e);
class ProducerT extends Thread
ProduceCosumeData p;
ProducerT(ProduceCosumeData p)
this.p=p; // i am saving the same obj for both threads
public void run()
p.printStringP(10); //it will print 10 times pay
class ConsumerT extends Thread
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p)
this.p=p; // i am saving the same obj for both threads
public void run()
p.printStringC(10); //it will print 10 times tm
我期待以下输出:
支付宝 支付宝 支付宝 ... 10 次
但我得到的输出是这样的:
支付..
接下来是漫长的等待。
以上两个函数在同一个对象中。 为什么 notify 没有释放 wait() 函数?即使我使用 notifyAll(),输出也保持不变。
【问题讨论】:
printStringP
可能会调用 notify
而 printStringC
仍在等待进入该方法(因为它已同步)。
【参考方案1】:
在您的代码中,您的一个线程正在调用通知,而另一个线程仍未等待。这会产生一个死锁,两个线程都在等待。
您需要修复您对同步标志的使用,如果不需要,请不要调用等待。此外,在 wait() 之后检查锁定条件仍然可用是一个好习惯。
这是你的ProduceConsumeData
类,使用了固定的标志:
class ProduceCosumeData
boolean flag;
public synchronized void printStringP(int n)
for(int i=0;i<n;i++)
try
while (flag == true)
wait();
flag=true;
System.out.print("Pay");
notify();
catch(Exception e)
System.out.print(e);
public synchronized void printStringC(int n)
for(int i=0;i<n;i++)
try
while(flag == false)
wait();
System.out.print("Tm");
flag = false;
notify();
catch(Exception e)
System.out.print(e);
【讨论】:
它工作正常。谢谢你。现在我学习了 2 个概念 1) 解除锁代码 2) 如何解决死锁 还有一个问题,为什么你使用 while (flag == true) wait();我们也可以使用 if(flag == true) wait(); 使用 if 有什么问题吗? @Yugandhar 您可以使用if
而不是while
,但最好在wait()
之后再次检查条件。例如,如果修改了类以添加更多功能并且在其他地方使用了类的锁,那么您的同步将被破坏。如果您在wait()
之后再次检查条件,代码会更加健壮
@Yugandhar Deadlock 表示两个或多个线程,每个线程都在等待其他线程做某事。但是使您陷入僵局的问题称为丢失通知,在这种情况下您必须学会避免这种情况。 ***.com/questions/24655143/…【参考方案2】:
您在方法中使用了通用wait()
与同步。尝试使用对象同步的版本,例如synchronized(this) wait();
等等,以防止多个线程对同一对象的循环依赖,这对于任何多线程程序来说都是非常危险的。
或者,更简单地说,在你的ProducerConsumerData
类中实现一个适当的clone()
方法,然后将这个对象传递给第一个线程,然后传递它的克隆。尝试在第二个线程的构造函数中使用p.clone()
而不是p
。
如上所述,您可以让 printStringP() 的 notify() 仅在 flag 为真时被调用,并非总是如此。
【讨论】:
据我所知,在这种情况下没有 diff b/w 同步方法或块【参考方案3】:这是一个经典的误解,几乎所有尝试使用wait
和notify
的人都会犯错。真的,他们太老了,太破了,恕我直言,他们甚至不应该被教导。
当printStringP
调用notify()
printStringC
还没有等待。
class ProduceCosumeData
// Variable shared between threads should be volatile.
volatile boolean flag;
public synchronized void printStringP(int n)
for (int i = 0; i < n; i++)
try
//for frist time flag is flase so, wait will skip
if (flag)
System.err.println("Waiting in printStringP");
wait();
else
System.err.println("flag now true");
flag = true; //for next time onwards wait() will get call
System.out.print("Pay");
System.err.println("printStringP notify");
notify();//after this why my wait() not canceling in inprintStringC()
catch (Exception e)
System.out.print(e);
public synchronized void printStringC(int n)
for (int i = 0; i < n; i++)
try
System.err.println("Waiting in printStringC");
wait(); // why it is not out of this after notify()
System.out.print("Tm");
System.err.println("printStringC notify");
notify();
catch (Exception e)
System.out.print(e);
class ProducerT extends Thread
ProduceCosumeData p;
ProducerT(ProduceCosumeData p)
this.p = p; // i am saving the same obj for both threads
public void run()
p.printStringP(10); //it will print 10 times pay
class ConsumerT extends Thread
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p)
this.p = p; // i am saving the same obj for both threads
public void run()
p.printStringC(10); //it will print 10 times tm
public void test()
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt = new ProducerT(p); // with p obj i am creating thread
ConsumerT ct = new ConsumerT(p); // with same p obj i am creating thread
pt.start();
ct.start(); //i am starting 2 threads
打印
flag now true
PayprintStringP notify
Waiting in printStringP
Waiting in printStringC
要解决此问题不要使用等待/通知,除了非常有经验的人外,其他所有人都无法使用它。使用Lock
s 和Condition
s 或几乎任何其他java.util.concurrent
类可以稳定地实现相同的功能。
【讨论】:
【参考方案4】:在printStringP
的第二次迭代中,flag
属性为true
,然后两个线程正在等待。
【讨论】:
您需要持有锁才能调用wait
。【参考方案5】:
Please find the below code snippet.
package com.java.examples;
public class ProducerConsumer
public static void main(String[] args) throws InterruptedException
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt = new ProducerT(p); // with p obj i am creating thread
ConsumerT ct = new ConsumerT(p); // with same p obj i am creating thread
pt.start();
Thread.sleep(1000);
ct.start(); // i am starting 2 threads
class ProduceCosumeData
boolean flag = false;
public synchronized void printStringP(int n)
for (int i = 0; i < n; i++)
try
if (flag)
notify();
else
flag = true;
System.out.println("Pay");
if (i <= n - 1)
wait();
else
break;
catch (Exception e)
System.out.print(e);
notify();
public synchronized void printStringC(int n)
for (int i = 0; i < n; i++)
try
if (flag)
System.out.println("Tm");
if (i <= n - 1)
notify();
else
break;
else
flag = false;
wait();
catch (Exception e)
System.out.print(e);
class ProducerT extends Thread
ProduceCosumeData p;
ProducerT(ProduceCosumeData p)
this.p = p; // i am saving the same obj for both threads
public void run()
p.printStringP(10); // it will print 10 times pay
class ConsumerT extends Thread
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p)
this.p = p; // i am saving the same obj for both threads
public void run()
p.printStringC(10); // it will print 10 times tm
【讨论】:
以上是关于为啥在我的 java 代码中没有调用通知的主要内容,如果未能解决你的问题,请参考以下文章
为啥我只能在我的 android 通知中按一次播放/暂停按钮?