【问题标题】:Printing values from different threads using wait and notify使用等待和通知从不同线程打印值
【发布时间】:2016-02-08 16:47:02
【问题描述】:


我有三个线程 ThreadA、ThreadB 和 ThreadC 分别在循环中打印值 A、B 和 C。
我希望输出类似于 A、B、C,然后再 A、B 和 C 直到循环正在线程中执行。我想使用等待和通知来编写这个示例程序。下面的代码正在打印所需的输出,但有时我只是在输出中看到“A”,我无法弄清楚这种情况。

public class ThreadOrder {

    public static void main(String[] args) {
        Object lockAB = new Object();
        Object lockBC = new Object();
        Object lockCA = new Object();

        Thread threadA = new Thread(new ThreadOrder().new ThreadA(lockAB, lockCA));
        Thread threadB = new Thread(new ThreadOrder().new ThreadB(lockAB, lockBC));
        Thread threadC = new Thread(new ThreadOrder().new ThreadC(lockBC, lockCA));

        threadA.start();
        threadB.start();
        threadC.start();
    }

    class ThreadA implements Runnable {
        Object lockAB;
        Object lockCA;

        public ThreadA(Object lockAB, Object lockCA) {
            this.lockAB = lockAB;
            this.lockCA = lockCA;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                if(i!=0) {
                    try {
                        synchronized (lockCA) {
                            lockCA.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                synchronized (lockAB) {
                    lockAB.notify();
                }
            }
        }

    }

    class ThreadB implements Runnable {
        Object lockAB;
        Object lockBC;

        public ThreadB(Object lockAB, Object lockBC) {
            this.lockAB = lockAB;
            this.lockBC = lockBC;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                try {
                    synchronized (lockAB) {
                        lockAB.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B");
                synchronized (lockBC) {
                    lockBC.notify();
                }
            }
        }

    }

    class ThreadC implements Runnable {
        Object lockBC;
        Object lockCA;

        public ThreadC(Object lockBC, Object lockCA) {
            this.lockBC = lockBC;
            this.lockCA = lockCA;
        }

        @Override
        public void run() {
            for(int i=0; i<3; i++) {
                try {
                    synchronized (lockBC) {
                        lockBC.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("C");
                synchronized (lockCA) {
                    lockCA.notify();
                }
            }
        }

    }
}

【问题讨论】:

标签: java multithreading wait notify


【解决方案1】:

你打电话给wait,但你还没有测试是否有什么需要等待的。你打电话给notify,但你没有改变任何你需要通知另一个线程的东西。您拥有所有这些synchronized 方法,但没有用于同步保护的共享状态。

您的代码中没有任何意义,您似乎根本不了解wait/notify 机制的作用。 wait 函数允许线程等待某个共享状态改变,notify 函数允许一个线程告诉其他线程某些共享状态已经改变。但是必须有一些共享状态,因为wait/notify 机制(与锁或信号量不同)在内部是无状态的。

您可能应该拥有一些受同步保护的共享状态。它应该编码接下来应该去哪个线程。如果您需要打印,但共享状态显示轮不到您,那么您可以通过 wait 获得一些东西。当您打印并使其接下来轮到其他线程打印时,您就有了notify 其他线程的内容。

【讨论】:

    【解决方案2】:

    考虑创建一个通过阻塞队列相互连接的线程环。然后你可以在环周围传递一个令牌。每个线程等待接收令牌,打印其输出,将令牌传递给环中的下一个线程,然后返回等待。

    【讨论】:

      【解决方案3】:
      package com.test.algorithms;
      
      import java.util.Arrays;
      import java.util.LinkedList;
      import java.util.Queue;
      
      public class PrintInOrder {
      
          private static Integer[] a = { 1, 1, 1 };
          private static Integer[] b = { 2, 2, 2 };
          private static Integer[] c = { 3, 3, 3 };
          private static Integer[] d = { 4, 4, 4 };
      
          public static void main(String[] args) throws InterruptedException {
      
              QueueOrder q1 = null;
              QueueOrder q2 = null;
              QueueOrder q3 = null;
              QueueOrder q4 = null;
      
              q1 = new QueueOrder(a);
              q2 = new QueueOrder(b);
              q3 = new QueueOrder(c);
              q4 = new QueueOrder(d);
      
              q1.setChild(q2);
      
              q2.setChild(q3);
      
              q3.setChild(q4);
      
              q4.setChild(q1);
      
              Thread t1 = new Thread(q1);
              Thread t2 = new Thread(q2);
              Thread t3 = new Thread(q3);
              Thread t4 = new Thread(q4);
      
      
              t1.start();
              t2.start();
              t3.start();
              t4.start();
      
              QueueOrder q = q1;
      
              while (!q.queue.isEmpty()) {
      
                  synchronized (q) {
                      if (!q.isPrinted) {
                          q.notify();
                          q.wait();
                      }
                  }
                  q = q.child;
              }
      
              t1.join();
              t2.join();
              t3.join();
              t4.join();
      
          }
      
      }
      
      class QueueOrder implements Runnable {
      
          Integer[] arr;
          QueueOrder child;
          Queue<Integer> queue = new LinkedList<>();
          boolean isPrinted = false;
      
          QueueOrder(Integer[] arr) {
              this.arr = arr;
              queue.addAll(Arrays.asList(arr));
          }
      
          public QueueOrder getChild() {
              return child;
          }
      
          public void setChild(QueueOrder child) {
              this.child = child;
          }
      
          public void run() {
      
              while (!this.queue.isEmpty()) {
      
                  synchronized (this) {
                      if (!this.isPrinted) {
                          try {
                              this.wait();
                          } catch (InterruptedException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                          }
                      } 
                  }
      
                  System.out.print("**" + this.queue.poll());
                  this.isPrinted = false;
                  synchronized (this) {
                      this.notify();
                  }
      
              }
          }
      }
      

      【讨论】:

        【解决方案4】:
        package com.test.algorithms;
        
        import java.util.Arrays;
        import java.util.LinkedList;
        import java.util.Queue;
        
        public class PrintInOrder1 {
        
            private static Integer[] a = { 1, 1, 1 };
            private static Integer[] b = { 2, 2, 2 };
            private static Integer[] c = { 3, 3, 3 };
            private static Integer[] d = { 4, 4, 4 };
        
            public static void main(String[] args) throws InterruptedException {
        
                QueueOrder1 q1 = null;
                QueueOrder1 q2 = null;
                QueueOrder1 q3 = null;
                QueueOrder1 q4 = null;
        
                q1 = new QueueOrder1(a);
                q2 = new QueueOrder1(b);
                q3 = new QueueOrder1(c);
                q4 = new QueueOrder1(d);
        
                q1.setChild(q2);
                q1.isPrinted = true;
        
                q2.setChild(q3);
        
                q3.setChild(q4);
        
                q4.setChild(q1);
        
                Thread t1 = new Thread(q1);
                Thread t2 = new Thread(q2);
                Thread t3 = new Thread(q3);
                Thread t4 = new Thread(q4);
        
        
                t1.start();
                t2.start();
                t3.start();
                t4.start();
        
        
        
                t1.join();
                t2.join();
                t3.join();
                t4.join();
        
            }
        
        }
        
        class QueueOrder1 implements Runnable {
        
            Integer[] arr;
            QueueOrder1 child;
            Queue<Integer> queue = new LinkedList<>();
            boolean isPrinted = false;
        
            QueueOrder1(Integer[] arr) {
                this.arr = arr;
                queue.addAll(Arrays.asList(arr));
            }
        
            public QueueOrder1 getChild() {
                return child;
            }
        
            public void setChild(QueueOrder1 child) {
                this.child = child;
            }
        
            public void run() {
        
                while (!this.queue.isEmpty()) {
        
                    synchronized (this) {
                        if (!this.isPrinted) {
                            try {
                                this.wait();
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        } 
                    }
        
                    System.out.print("**" + this.queue.poll());
                    this.isPrinted = false;
                    synchronized (this.child) {
                        if(!this.child.isPrinted) {
                            this.child.notify();
                        }
                    }
        
                }
            }
        }
        

        【讨论】:

        • 你能解释一下你在做什么吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-20
        • 2015-11-06
        • 1970-01-01
        • 2020-08-31
        • 1970-01-01
        • 2019-08-27
        相关资源
        最近更新 更多