Synchronisation using wait() and notify()

问题: I need to print the following pattern using 3 different threads such that: Thread 1 prints "I" Thread 2 prints "LOVE" Thread 3 prints "EARTH" I LOVE EARTH I LOVE E...

问题:

I need to print the following pattern using 3 different threads such that:

Thread 1 prints "I"

Thread 2 prints "LOVE"

Thread 3 prints "EARTH"

I LOVE EARTH
I LOVE EARTH
I LOVE EARTH

using wait() and notify() methods. I have started with the following code but it seems it is printing only once since all of them are waiting at the end of the first iteration of each loop.

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();

}


}

Can someone please explain how to go about this problem?


回答1:

I have fixed your code. You have put the "m.notify()" after "m.wait()" so they all wait for each other. I gently moved it before "m.wait()" and converted the for loop to an endless while loop to make the threads run forever.

Update1

I have updated the code so that the threads write the text for three times.

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();

    }

}

回答2:

Object.notify() picks a random thread to wake up. Your code works one time because of the sleeps between the starts, you artificially ensure the expected order of execution.

You should rather use notifyAll(), waking all threads, and because of that, the threads should wait() in a loop, until their turn has arrived:

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();

The if from the start has been removed, as in real concurrent execution there is no guarantee to have the expected value in word. Then one of the threads grabs the lock, checks if word is its own one, and either start waiting, or prints its text and steps word to the next phase, waking up the other threads (both of them, with notifyAll()). Then it either exits, or proceeds to the wait() again. This is an important part: I wanted to modify your code as less as possible, so everything happens inside the synchronized blocks, meaning that threads can run only when the other two are waiting or finished. For this lock-stepping it works, but in general the synchronized block should rather be inside the for loop, perhaps two separate blocks, one around the equals-wait loop, and another one around the set+notifyAll statements.

  • 发表于 2018-07-10 01:51
  • 阅读 ( 149 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除