使用wait()和notify()进行同步

时间:2018-07-08 10:41:09

标签: java multithreading

我需要使用3个不同的线程来打印以下图案:

线程1打印“ I”

线程2打印“ LOVE”

线程3打印“ EARTH”

I LOVE EARTH
I LOVE EARTH
I LOVE EARTH

使用wait()和notify()方法。 我从下面的代码开始,但是似乎它们只打印一次,因为它们都在每个循环的第一次迭代结束时等待。

public class MultiThreading_2 {
static volatile boolean flag=false;
static volatile String  word = "I";


public static void main(String[] args) throws InterruptedException {

    MultiThreading_2 m = new MultiThreading_2();


    Runnable a = new Runnable() {

        public void run() {
            if(word.equals("I"))
            {
                synchronized(m)
                {
                for(int i=1;i<=2;i++) {

                    if(word.equals("I"))    {   
                        System.out.println("I ");
                        word="LOVE";

                        try {
                            m.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    m.notify();

                }

                }
                }
        }


    };

    Runnable b = new Runnable() {

        public void run() {

            if(word.equals("LOVE"))
            {
                synchronized(m)
                {

                for(int j=1;j<=2;j++) {

                    if(word.equals("LOVE")) {
                        System.out.println("LOVE ");
                        word="WORLD";
                        try {
                            m.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        m.notify();


                    }

                }


                }
                }
        }



    };

    Runnable c = new Runnable() {

        public void run() {

            if(word.equals("WORLD"))
            {
                synchronized(m)
                {

                for(int k=1;k<=2;k++) {
                        System.out.println("WORLD ");
                        word="I";
                        try {
                            m.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                            m.notify();



                    }


                }

                }
                }



    };


    new Thread(a).start();
    Thread.sleep(100);
    new Thread(b).start();
    Thread.sleep(100);
    new Thread(c).start();

}


}

有人可以解释如何解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

我已修复您的代码。您已将“ m.notify()”放在“ m.wait()”之后,因此它们都互相等待。我在“ m.wait()”之前轻轻移动了它,并将for循环转换为无尽的while循环,以使线程永远运行。

更新1

我已经更新了代码,以便线程将文本写入3次。

public class MultiThreading_2 {
    static volatile boolean flag = false;
    static volatile String word = "I";

    public static void main(String[] args) throws InterruptedException {

        MultiThreading_2 m = new MultiThreading_2();

        Runnable a = new Runnable() {

            public void run() {

                for (int i = 0; i < 3; i++) {
                    synchronized (m) {
                        if (word.equals("I")) {
                            System.out.print("I ");
                            word = "LOVE";

                            m.notify();
                            try {
                                m.wait();
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        } else {
                            i--;
                        }

                    }

                }
            }

        };

        Runnable b = new Runnable() {

            public void run() {

                for (int i = 0; i < 3; i++) {
                    synchronized (m) {
                        if (word.equals("LOVE")) {
                            System.out.print("LOVE ");
                            word = "WORLD";
                            m.notify();
                            try {
                                m.wait();
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }

                        } else {
                            i--;
                        }

                    }

                }
            }

        };

        Runnable c = new Runnable() {

            public void run() {

                for (int i = 0; i < 3; i++) {
                    synchronized (m) {
                        if (word.equals("WORLD")) {
                            System.out.println("WORLD ");
                            word = "I";
                            m.notify();
                            try {
                                m.wait();
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }

                        } else {
                            i--;
                        }
                    }

                }

            }

        };

        new Thread(a).start();
        Thread.sleep(100);
        new Thread(b).start();
        Thread.sleep(100);
        new Thread(c).start();

    }

}

答案 1 :(得分:1)

Object.notify()选择一个随机线程唤醒。由于两次启动之间的睡眠,您的代码只能工作一次,因此您可以人为地确保预期的执行顺序。

您应该使用notifyAll()唤醒所有线程,因此,线程wait()应该循环循环,直到轮到为止:

Runnable a = new Runnable() {
  public void run() {
    synchronized (m) {
      for (int i = 1; i <= 2; i++) {
        while(!word.equals("I"))
          try{
            m.wait();
          }
          catch(InterruptedException ie){
            ie.printStackTrace();
          }
        System.out.print("I ");
        word = "LOVE";
        m.notifyAll();
      }
    }
  }
};

Runnable b = new Runnable() {
  public void run() {
    synchronized (m) {
      for (int i = 1; i <= 2; i++) {
        while(!word.equals("LOVE"))
          try{
            m.wait();
          }
          catch(InterruptedException ie){
            ie.printStackTrace();
          }
        System.out.print("LOVE ");
        word = "WORLD";
        m.notifyAll();
      }
    }
  }
};

Runnable c = new Runnable() {
  public void run() {
    synchronized (m) {
      for (int i = 1; i <= 2; i++) {
        while(!word.equals("WORLD"))
          try{
            m.wait();
          }
          catch(InterruptedException ie){
            ie.printStackTrace();
          }
        System.out.println("WORLD ");
        word = "I";
        m.notifyAll();
      }
    }
  }
};

new Thread(a).start();
new Thread(b).start();
new Thread(c).start();

if从一开始就被删除,因为在真正的并发执行中,不能保证word中具有期望的值。然后,其中一个线程抓住该锁,检查word是否是它自己的那个线程,然后开始等待,或者打印其文本,然后将word打印到下一个阶段,从而唤醒其他线程(与notifyAll())。然后它退出,或再次进入wait()。这是重要的部分:我想尽可能少地修改代码,以便所有事情都在同步块内发生,这意味着线程仅在其他两个正在等待或完成时才可以运行。对于这种锁定步骤,​​它可以工作,但通常来说,同步块应该位于for循环内,也许是两个单独的块,一个围绕equals-wait循环,另一个围绕set + notifyAll语句。