有效地使用Java中的两个线程打印奇数和偶数?

时间:2018-10-12 17:43:27

标签: java multithreading concurrency thread-safety runnable

在采访中我被问到以下问题,我需要使用两个线程打印出偶数和奇数,因此我想出了下面的代码,但是在此我使用了两个类,一个实现可运行的接口,另一个用于打印使用waitnotifyAll的数字。

public class PrintEvenOddTester {

  public static void main(String[] args) {
    Output print = new Output();
    Thread t1 = new Thread(new EvenOddTask(print, 10, false));
    Thread t2 = new Thread(new EvenOddTask(print, 10, true));
    t1.start();
    t2.start();
  }
}


class EvenOddTask implements Runnable {
  private int max;
  private Output print;
  private boolean isEvenNumber;

  EvenOddTask(Output print, int max, boolean isEvenNumber) {
    this.print = print;
    this.max = max;
    this.isEvenNumber = isEvenNumber;
  }

  @Override
  public void run() {
    int number = isEvenNumber == true ? 2 : 1;
    while (number <= max) {
      if (isEvenNumber) {
        print.printEven(number);
      } else {
        print.printOdd(number);
      }
      number += 2;
    }
  }
}


class Output {
  boolean isOdd = false;

  public synchronized void printEven(int number) {
    while (isOdd == false) {
      try {
        wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("Even:" + number);
    isOdd = false;
    notifyAll();
  }

  public synchronized void printOdd(int number) {
    while (isOdd == true) {
      try {
        wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("Odd:" + number);
    isOdd = true;
    notifyAll();
  }
}

我想检查在Java 7中是否有更好或更简单的方法来完成这些任务。通常,我不能直接在Output中打印而不是使用另一个EvenOddTask类上课?

1 个答案:

答案 0 :(得分:1)

您可以通过以下方式进行操作:

  1. 不使用同步:

    class Print {
    
        private static int count = 1;
        private static int MAX = 20;
        private boolean isOdd = true;
    
        public void printEven() {
            while (true) {
                if (count > MAX) break;
                if (!isOdd) {
                    System.err.println(Thread.currentThread().getName() + ":" + count++);
                    isOdd = true;
                }
            }
        }
    
        public void printOdd() {
            while (true) {
                if (count > MAX) break;
                if (isOdd) {
                    System.err.println(Thread.currentThread().getName() + ":" + count++);
                    isOdd = false;
                }
            }
        }
    
    }
    
    public class ThreadOddEven {
        public static void main(String[] args) {
            Print p = new Print();
    
            // Thread t1 = new Thread(() -> p.printEven());
            Thread t1 = new Thread(new Runnable() {     
               @Override
               public void run() {
                  p.printEven();                
               }
            });
            t1.setName("EVEN");
    
            // Thread t2 = new Thread(() -> p.printOdd());
            Thread t2 = new Thread(new Runnable() {
               @Override
               public void run() {
                  p.printOdd(); 
               }
            });
            t2.setName("ODD");
    
            t1.start();
            t2.start();
        }
    
    }
    

    这可能是实现奇数和奇数打印的最简单方法 两个线程上的偶数。

    在这里,我们仅使用布尔变量isOdd。该值得到 在每个线程打印值之后切换。

  2. 使用同步:

    class Print2 {
    
        private static int count = 1;
        private static int MAX = 10;
        private Object obj = new Object();
    
        public void printEven() {
            while (true) {
                if (count > MAX) break;
                synchronized (obj) {
                    System.err.println(Thread.currentThread().getName() + " : " + count++);
                    obj.notify();
                    try {
                        obj.wait();
                    } catch (InterruptedException e) { }
                }
            }
        }
    
        public void printOdd() {
            while (true) {
                if (count > MAX) break;
                synchronized (obj) {
                    System.err.println(Thread.currentThread().getName() + " : " + count++);
                    obj.notify();
                    try {
                        obj.wait();
                    } catch (InterruptedException e) { }
                }
            }
        }
    
    }
    

    在第二个示例中,我们不使用布尔变量,而是 使用对象,以便我们可以同步两者之间的调用 线程。

    对该类的主要方法调用与上面的示例相同。