【问题标题】:print odd and even numbers using two threads in java efficiently?使用java中的两个线程有​​效地打印奇数和偶数?
【发布时间】:2019-03-17 23:39:09
【问题描述】:

我在一次采访中被问到下面的问题,我需要使用两个线程打印出偶数和奇数,所以我想出了下面的代码,但在这里我使用两个类,一个实现可运行接口,另一个打印出使用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 中是否有更好或更简单的方法来完成这些任务。一般情况下,我可以不直接在 EvenOddTask 类中打印而不是使用另一个 Output 类吗?

【问题讨论】:

    标签: java multithreading concurrency thread-safety runnable


    【解决方案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) { }
                  }
              }
          }
      
      }
      

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

      这个类的main方法调用同上例。

    【讨论】:

    • 这看起来要简单得多。非常感谢。我唯一的困惑是我们这里没有任何同步和锁,所以这是如何工作的?我的意思是它如何在没有线程之间任何同步的情况下先打印出奇数,然后再打印出奇数?另外,如果可能的话,您能否在 Java 7 中编辑此示例以便我更好地理解?
    • lambdas 似乎只在 Java 8 中添加
    • 是的,我也很困惑,因为我没有看到任何同步。我认为我们可能需要在两个线程之间进行同步,并至少将volatile 用于countisOdd 变量。
    • 因为它是语言规范所要求的。 “我试过一次,它有效”是一种糟糕的测试方式。您在两个线程之间共享数据(字段);你必须同步。
    • @flash :请检查编辑。 你可以在下次面试时解释这两种方法,让面试官大吃一惊
    猜你喜欢
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多