【问题标题】:Odd even number printing using thread使用线程打印奇偶数
【发布时间】:2011-08-26 09:55:41
【问题描述】:

奇偶数打印使用线程。创建一个线程类,两个线程实例。一个打印奇数,另一个打印偶数。

我做了以下编码。但它涉及死锁状态。有人可以解释一下这可能是什么原因吗?

public class NumberPrinter implements Runnable{
private String type;
private static boolean oddTurn=true;


public NumberPrinter(String type){
    this.type=type;
}
public void run() {
    int i=type.equals("odd")?1:2;
    while(i<10){
        if(type.equals("odd"))
            printOdd(i);
        if(type.equals("even"))
            printEven(i);
        i=i+2;
    }

}

private synchronized void printOdd(int i){
    while(!oddTurn){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(type + i);
    oddTurn=false;
    notifyAll();
}

private synchronized  void printEven(int i){
    while(oddTurn){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace(); 
        }
    }
    System.out.println(type + i);
    oddTurn=true;
    notifyAll();

}

public static void main(String[] s){
    Thread odd=new Thread(new NumberPrinter("odd"));
    Thread even=new Thread(new NumberPrinter("even"));
    odd.start();
    even.start();

}
}

输出: 奇数1 偶数2


然后陷入僵局!!!!!!

感谢您的帮助。

【问题讨论】:

  • 这是作业吗?如果是这样,请将标签“作业”添加到您的问题中。
  • 为什么是这个标记算法?

标签: java multithreading thread-safety


【解决方案1】:

您正在等待并通知不同的对象(监视器)。

这个想法是你可以打电话给obj.wait() 等待某人做obj.notify(),而你正在做objA.wait()objB.notify()

将您的 printOdd 方法更改为类似

private void printOdd(int i) {
    synchronized (lock) {                        // <-------
        while (!oddTurn) {
            try {
                lock.wait();                     // <-------
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(type + i);
        oddTurn = false;
        lock.notifyAll();                        // <-------
    }
}

printEven 方法类似。

然后为NumberPrinter 提供lock 对象:

Object lock = new Object();
Thread odd = new Thread(new NumberPrinter("odd", lock));
Thread even = new Thread(new NumberPrinter("even", lock));

输出:

odd1
even2
odd3
even4
odd5
even6
odd7
even8
odd9

【讨论】:

    【解决方案2】:

    代码中有很多错误。

    首先,synchronized 语句没有任何作用。您创建两个线程实例,每个实例只调用自己的方法。 synchronized 仅在 另一个 线程可以调用方法时才有用。

    然后notifyAll() 没有效果,原因相同。 odd.notifyAll() 达不到 even 挂在 wait() 中。

    所以你需要的是另一个包含状态并且两个线程都可以看到和使用的对象。在第三个实例上使用 synchronizedwait()notifyAll()

    【讨论】:

    • 在这种情况下,您不需要让公共对象包含任何状态。看我的回答。
    • 确实如此,但它使查看两个线程之间共享的状态变得更加简单。多线程编程已经足够复杂而不会增加更多复杂性:-)
    • 同意。除非它们是某些家庭作业的一部分,否则此类任务也应该使用java.util.concurrent 包进行编码:)
    【解决方案3】:

    同样可以使用Lock接口解决:

    NaturalOrder.java

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class NaturalOrder {
    
        public int currentNumber = 1;
        public boolean evenOdd = false;
    
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
    
        public static void main(String[] args) {
            NaturalOrder naturalOrder = new NaturalOrder();
            Thread t1 = new Thread(new OddNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
            Thread t2 = new Thread(new EvenNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
            t1.start();
            t2.start();
        }
    }
    

    OddNumberLock.java

    import java.util.concurrent.ThreadLocalRandom;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class OddNumberLock implements Runnable {
    
        NaturalOrder naturalOrder;
        Lock lock;
        Condition condition;
    
        public OddNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
            this.naturalOrder = naturalOrder;
            this.lock = lock;
            this.condition = condition;
        }
    
        @Override
        public void run() {
            lock.lock();
            while (naturalOrder.currentNumber < 20) {
                while (naturalOrder.evenOdd != false) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                try {
                    Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (naturalOrder.currentNumber % 2 != 0) {
                    System.out.println(naturalOrder.currentNumber);
                }
                naturalOrder.currentNumber++;
                naturalOrder.evenOdd = true;
    
                condition.signalAll();
            }
            lock.unlock();
        }
    }
    

    EvenNumberLock.java

    import java.util.concurrent.ThreadLocalRandom;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class EvenNumberLock implements Runnable {
    
        NaturalOrder naturalOrder;
        Lock lock;
        Condition condition;
    
        public EvenNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
            this.naturalOrder = naturalOrder;
            this.lock = lock;
            this.condition = condition;
        }
    
        @Override
        public void run() {
            lock.lock();
            while (naturalOrder.currentNumber < 20) {
                while (naturalOrder.evenOdd != true) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                try {
                    Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                if (naturalOrder.currentNumber % 2 == 0) {
                    System.out.println(naturalOrder.currentNumber);
                }
                naturalOrder.currentNumber++;
                naturalOrder.evenOdd = false;
                condition.signalAll();
            }
            lock.unlock();
        }
    }
    

    【讨论】:

      【解决方案4】:

      我认为问题可能是printOddprintEven 在不同的锁上同步(线程的对象实例锁)。因此,您不能保证静态变量 oddTurn 的更改将在另一个线程中可见。尝试让 oddTurn 开始时为 volatile。

      【讨论】:

        【解决方案5】:

        我是这样做的

        public class OddEven{
                public static void main(String[] args){
                    Print o=new Print();
                    Thread even=new Thread(new MyRunnable(2,o));
                    Thread odd=new Thread(new MyRunnable(1,o));
                    even.start();
                    odd.start();
                }
        }
        class MyRunnable implements Runnable{
                int start;
                Print ob;
                MyRunnable(int s,Print o){
                    start=s;
                    ob=o;
                }
                public void run(){
                    for(int i=start;i<=20;i+=2)
                        ob.display(i);
                }   
        }
        class Print{
                int rem=0;
                synchronized void display(int n){
                    while(n%2==rem)
                        try{
                            wait();
                        }
                        catch(Exception e){System.out.println("Display interrupted");}
                    System.out.print(n+" ");
                    rem=n%2;
                    notify();
                }           
        }
        

        【讨论】:

          【解决方案6】:

          您在 oddTurn 变量中缺少 volatile 关键字。没有它,就无法保证线程看到实际值。

          【讨论】:

          • 感谢您的回复。即使在使用 volatile 之后也得到了相同的结果。它将陷入僵局。
          • 查看其他答案,我错过了一个事实,即你有两个对象,所以没有执行真正的同步。
          • volatile 没关系。两个线程访问不同的变量。
          【解决方案7】:

          我使用共享对象来控制执行顺序

          class Counter implements Runnable {
            int count;
            static Class cl = Counter.class;
          
            public synchronized void increment() {
                  String tname = Thread.currentThread().getName();
                  System.out.printf("%s: %d\n", tname, count++);
            }
          
            @Override
            public void run() {
                  String tname = Thread.currentThread().getName();
                  while (true) {
          
                        increment();
                        synchronized (Counter.class) {
                              try {
                                    cl.notify();
                                    cl.wait();
                              } catch (Exception e) {
                                    e.printStackTrace();
                              }
                        }
          
                  }
            }
          }
          
          public class WaitNotify {
          public static void main(String[] args) {
              Counter c = new Counter();
              Thread t1 = new Thread(c, "thread1");
              Thread t2 = new Thread(c, "thread2");
              t1.start();
              t2.start();
          }
          }
          

          【讨论】:

            【解决方案8】:

            这是我的解决方案,无需等待或通知。 wait() 和 notify()/notifyAll() ,
            我看不出有任何理由在这个问题陈述中使用它们。

            package threading;
            
            import java.util.concurrent.ExecutorService;
            import java.util.concurrent.Executors;
            
            public class EvenOddPrinting {
            
                int count=0;
                boolean isOdd = false;
            
                public static void main(String[] args) {
                    ExecutorService exec = Executors.newCachedThreadPool();
                    EvenOddPrinting obj = new EvenOddPrinting();
                    exec.submit(new EvenPrinter(obj));
                    exec.submit(new OddPrinter(obj));
                    exec.shutdown();
            
            
            
                }
            
            }
            
            class EvenPrinter implements Runnable{
                EvenOddPrinting obj;
                public EvenPrinter(EvenOddPrinting obj) {
                    this.obj=obj;
                }
            
                @Override
                public void run() {
                    while(obj.count < 100){
                        if(!obj.isOdd){
                            System.out.println("Even:"+obj.count);
                            obj.count++;
                            obj.isOdd = true;
                        }
                    }
            
                }
            }
            
            
            class OddPrinter implements Runnable{
            
                EvenOddPrinting obj;
                public OddPrinter(EvenOddPrinting obj) {
                    this.obj = obj;
                }
            
                @Override
                public void run() {
                    while(obj.count < 100){
                        if(obj.isOdd){
                            System.out.println("Odd:"+obj.count);
                            obj.count++;
                            obj.isOdd = false;
                        }
                    }
                }
            }
            

            【讨论】:

              【解决方案9】:

              使用 Lock 界面更正了您的代码:

              import java.util.concurrent.locks.Condition;
              import java.util.concurrent.locks.Lock;
              import java.util.concurrent.locks.ReentrantLock;
              
              public class NumberPrinter implements Runnable {
                  private Lock lock;
                  private Condition condition;
                  private String type;
                  private static boolean oddTurn = true;
              
                  public NumberPrinter(String type, Lock lock, Condition condition) {
                      this.type = type;
                      this.lock = lock;
                      this.condition = condition;
                  }
              
                  public void run() {
                      int i = type.equals("odd") ? 1 : 2;
                      while (i <= 10) {
                          if (type.equals("odd"))
                              printOdd(i);
                          if (type.equals("even"))
                              printEven(i);
                          i = i + 2;
                      }
                  }
              
                  private void printOdd(int i) {
                      // synchronized (lock) {
                      lock.lock();
                      while (!oddTurn) {
                          try {
                              // lock.wait();
                              condition.await();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
                      System.out.println(type + " " + i);
                      oddTurn = false;
                      // lock.notifyAll();
                      condition.signalAll();
                      lock.unlock();
                  }
              
                  // }
              
                  private void printEven(int i) {
                      // synchronized (lock) {
                      lock.lock();
                      while (oddTurn) {
                          try {
                              // lock.wait();
                              condition.await();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }
                      System.out.println(type + " " + i);
                      oddTurn = true;
                      // lock.notifyAll();
                      condition.signalAll();
                      lock.unlock();
                  }
              
                  // }
              
                  public static void main(String[] args) {
                      Lock lock = new ReentrantLock();
                      Condition condition = lock.newCondition();
                      Thread odd = new Thread(new NumberPrinter("odd", lock, condition));
                      Thread even = new Thread(new NumberPrinter("even", lock, condition));
                      odd.start();
                      even.start();
                  }
              }
              

              【讨论】:

                【解决方案10】:
                public class Number_Thread extends Thread {
                
                String thread;
                int limit;
                
                public Number_Thread(String thread,int limit){
                    this.thread=thread;
                    this.limit=limit;
                                                             }
                
                Object lock=new Object();
                
                public  void run()
                {
                
                    synchronized (lock) 
                    {
                
                          //------------------- "print even"--------------------//
                
                      if(thread.equals("even"))
                        {
                            for (int i = 2; i <=limit; i+=2) 
                            {
                
                                 System.out.println(thread+" thread "+i);
                            try {
                
                            lock.wait(1000);
                                 continue;
                
                                }
                              catch (InterruptedException e) {}
                            }
                            lock.notifyAll();
                        }
                
                         //------------------- "print odd"--------------------//
                
                    if(thread.equals("odd"))
                         {
                         for (int i = 1; i <=limit; i+=2) 
                             {
                                System.out.println(thread+" thread  "+i);
                            try {
                
                                lock.wait(1000);
                                    continue;
                                }
                            catch (InterruptedException e) {}
                            }
                            lock.notifyAll();
                         }
                      }
                   }
                }
                
                     //------------------thread creater class------------------//
                import java.util.Scanner;
                
                public class Main_Thread {
                private static Scanner s;
                    public static void main(String[] args) throws InterruptedException {
                        System.out.print("enter limit:\t ");
                        s=new Scanner(System.in);
                    int n=s.nextInt();
                     s.close();
                    Thread t1=new Number_Thread("even",n);
                    Thread t2=new Number_Thread("odd",n);
                    t2.start();
                    Thread.sleep(100);
                    t1.start();
                
                 }
                
                }
                

                限制 5 的输出:

                输入限制:5

                奇数线程 1

                偶数线程 2

                奇数线程 3

                偶数线程 4

                奇数线程 5

                【讨论】:

                  【解决方案11】:

                  我已经以这种方式实现了,根据参数,不会产生线程,并且不会以循环方式产生相应的线程。 即,如果线程数为 3,线程 1 将打印 1,4 ...;线程 2 将打印 2,5,...,线程 3 将打印 3,6...

                  public class ThreadSynchronizer
                  {
                  
                      public static void main(String[] args)
                      {
                      // BASED ON THE ARGUMENT MULTIPLE THREADS WILL BE CREATED AND EACH WILL PRINT ITS RESPECTIVE NO
                      // IE, IF THREAD COUNT IS 3, THREAD 1 WILL PRINT 1,4 ..., THREAD2 WILL PRINT 2,5,... AND THREAD3 WILL PRINT 3,6...
                      // LIMITED THE DISPLAY TO 1000 NOS
                      int threadCnt = Integer.parseInt(args[0]);
                  
                      ReentrantLock lckArray[] = new ReentrantLock[threadCnt + 1];
                  
                      for (int i = 0; i < threadCnt + 1; i++)
                      {
                          ReentrantLock lck = new ReentrantLock();
                          lck.lock();
                          lckArray[i] = lck;
                      }
                  
                      for (int i = 0; i < threadCnt; i++)
                      {
                          Thread th = new Thread(new Printer(lckArray, i + 1));
                          th.start();
                      }
                  
                      for (int i = 1; i < threadCnt + 1; i++)
                      {
                          lckArray[i].unlock();
                  
                          while (!lckArray[i].isLocked())
                          {
                  
                          }
                      }
                      lckArray[0].unlock();
                      }
                  }
                  
                  class Printer implements Runnable
                  {
                  
                      private ReentrantLock[] lckArray;
                      private int index;
                  
                      Printer(ReentrantLock[] lckArray, int startValue)
                      {
                      this.lckArray = lckArray;
                      this.index = startValue;
                      }
                  
                      @Override public void run()
                      {
                      ReentrantLock prevLock = null;
                      int printCounter = index;
                  
                      for (int counter = 0; printCounter <= 1000; counter++)
                      {
                          int remCounter = counter % lckArray.length;
                          int incCounter = lckArray.length - remCounter;
                          int indexPostion = index + incCounter;
                          int curElementIndex = indexPostion % lckArray.length;
                  
                          lckArray[curElementIndex].lock();
                          if (prevLock != null)
                          prevLock.unlock();
                          prevLock = lckArray[curElementIndex];
                  
                          if (curElementIndex == 0)
                          {
                          System.out.println("Printed by Thread " + index + " " + printCounter);
                          printCounter = printCounter + lckArray.length - 1;
                          }
                  
                      }
                  
                      if (prevLock != null)
                      {
                          if (prevLock.isHeldByCurrentThread())
                          prevLock.unlock();
                      }
                  
                      }
                  
                  }
                  

                  【讨论】:

                    【解决方案12】:

                    两个线程的程序交替打印奇数和偶数。

                    #使用“对象锁定”概念实现。

                    class Increment{
                    private int count;
                        public void increment(){
                            count++;
                            System.out.println(Thread.currentThread().getName()+"::::::::::::::::::"+count);
                        }
                    }
                    
                    
                    class SimpleThread extends Thread{
                     
                     Increment obj = null;
                     
                     SimpleThread(Increment obj){
                        this.obj=obj;
                     }  
                     
                     public void run(){
                         try {
                        Thread.sleep(100);
                             while(true){
                                synchronized(obj){
                                       obj.increment();
                                       Thread.sleep(1000);
                                       obj.notify();
                                       obj.wait();  
                                }
                             }
                         } catch(InterruptedException ie) {
                            ie.printStackTrace(); 
                         }
                     } 
                     
                    }
                    
                    public class Main
                    {
                        public static void main(String[] args) {
                            
                            Increment increment = new Increment();
                            SimpleThread t1 = new SimpleThread(increment);
                            SimpleThread t2 = new SimpleThread(increment);
                           
                            t1.start();
                            t2.start();
                    
                            System.out.println(Thread.currentThread().getName()+"::::::::::::::"+"Hello World");
                            System.out.println(Runtime.getRuntime().availableProcessors()+"::::::::::::::"+"CORE SIZE");
                        }
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      我实现的很简单,从1到40>

                      public class EvenOddProblem {
                      
                          public static void main(String[] args) {
                              Printer p = new Printer();
                              EvenThread enenThread = new EvenThread(p);
                              OddThread oddThread = new OddThread(p);
                              new Thread(enenThread).start();
                              new Thread(oddThread).start();
                      
                          }
                      
                      }
                      
                      class EvenThread implements Runnable {
                          private Printer printer;
                      
                          public EvenThread(Printer p) {
                              printer = p;
                          }
                      
                          @Override
                          public void run() {
                              try {
                                  int i = 0;
                                  while (true) {
                                      if (i == 20)
                                          break;
                                      i++;
                      
                                      printer.evenPrintEven();
                                  }
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                      
                      }
                      
                      class OddThread implements Runnable {
                          private Printer printer;
                      
                          public OddThread(Printer p) {
                              printer = p;
                          }
                      
                          @Override
                          public void run() {
                              int i = 0;
                              try {
                                  while (true) {
                                      if (i == 20)
                                          break;
                                      i++;
                                      printer.evenPrintOdd();
                                  }
                              } catch (InterruptedException e) {
                                  e.printStackTrace();
                              }
                          }
                      
                      }
                      
                      class Printer {
                          private static volatile Integer i = 1;
                      
                          public synchronized void evenPrintOdd() throws InterruptedException {
                              while (i % 2 == 0) {
                                  wait();
                              }
                              System.out.println(i);
                              i++;
                              notifyAll();
                          }
                      
                          public synchronized void evenPrintEven() throws InterruptedException {
                              while (!(i % 2 == 0)) {
                                  wait();
                              }
                              System.out.println(i);
                              i++;
                              notifyAll();
                          }
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-10-15
                        • 1970-01-01
                        • 2013-05-17
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多