【问题标题】: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 可能会调用 notifyprintStringC 仍在等待进入该方法(因为它已同步)。

标签: java multithreading inter-process-communicat


【解决方案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 表示两个或多个线程,每个线程都在等待其他线程做某事。但是使您陷入僵局的问题称为丢失通知,在这种情况下您必须学会避免这种情况。 stackoverflow.com/questions/24655143/…
【解决方案2】:

您在方法中使用了通用wait() 与同步。尝试使用对象同步的版本,例如synchronized(this){ wait(); } 等等,以防止多个线程对同一对象的循环依赖,这对于任何多线程程序来说都是非常危险的。

或者,更简单地说,在你的ProducerConsumerData 类中实现一个适当的clone() 方法,然后将这个对象传递给第一个线程,然后传递它的克隆。尝试在第二个线程的构造函数中使用p.clone() 而不是p

如上所述,您可以让 printStringP() 的 notify() 仅在 flag 为真时被调用,并非总是如此。

【讨论】:

  • 据我所知,在这种情况下没有 diff b/w 同步方法或块
【解决方案3】:

这是一个经典的误解,几乎所有尝试使用waitnotify 的人都会犯错。真的,他们太老了,太破了,恕我直言,他们甚至不应该被教导。

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

要解决此问题不要使用等待/通知,除了非常有经验的人外,其他所有人都无法使用它。使用Locks 和Conditions 或几乎任何其他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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      • 2013-10-11
      • 1970-01-01
      • 2020-06-08
      • 2017-04-01
      • 2014-05-17
      • 1970-01-01
      相关资源
      最近更新 更多