NotifyAll 不工作

NotifyAll not working

此代码正在打印来自两个不同线程的 Even/Odd 数字。在这里,我的程序卡在 wait() 中,无法使用 notifyAll() 唤醒睡眠线程。

想知道为什么notifyAll无法唤醒所有休眠的线程? 需要知道我在这里做错了什么。

class EvenOddThread {
  public static void main (String [] args) {
  Runnable runnEven = new ThreadPrint (true, 10);
  Runnable runnOdd = new ThreadPrint (false, 10);

  Thread t1 = new Thread (runnEven);
  Thread t2 = new Thread (runnOdd);

  t1.start ();
  t2.start ();
  }
}

class ThreadPrint implements Runnable {
  private boolean isEvenPrint = false;
  private int maxPoint = 0;
  ThreadPrint (boolean isEven, int max) {
    isEvenPrint = isEven;
    maxPoint = max;
  }

  @Override
  public void run () {
    Print p = new Print();
    if (isEvenPrint)
      p.printEven(maxPoint);
    else
      p.printOdd(maxPoint);
  }
}

class Print {


  public synchronized void printEven (int maxPoint) {
    int even = 0;
    while (even <= maxPoint) {
      System.out.println(even);
      even = even + 2;
      try {
      wait();
    }
    catch (Exception e) {
      System.out.println(e);
    }

    notifyAll();
    }
  }

  public synchronized void printOdd (int maxPoint) {
    int odd = 1;
    while (odd <= maxPoint) {


    System.out.println(odd);
    odd = odd + 2;
    try {
      wait();
    }
    catch (Exception e) {
      System.out.println(e);
    }

      notifyAll();
    }
  }
}

谢谢, 希瓦姆

两个线程在打印第一个数字后都进入wait。由于两个线程都已暂停,因此两个线程都无法唤醒另一个。

为了让一对线程以这种方式交替,您可以有单独的条件来控制每个线程的进度。每个线程在完成自己的工作单元后会解除对另一个线程的阻塞。这可以通过 Semaphore, CyclicBarrier, or Phaser.

来完成

notifyAll() 应该通知所有等待特定对象的线程,而不是所有在任何地方等待的线程。您所做的是,为每个线程创建一个 Print 实例 - 然后使用不合格的 wait()、notifyAll() - 这意味着您的线程使用每个线程的本地变量进行通信。

所以首先你必须让他们使用相同的 synchronization/signaling 个对象。

其次,您至少需要提供一些初始启动。在这里要小心,因为当您确定至少其中一个已经在收听时,您需要发出此信号。最好的情况是确保他们都在听,这样你就可以避免无数可能的竞争条件情况。

=咆哮= Sun 在这里搞得一团糟,IMO,通过向程序员隐藏(互斥锁、条件、信号)三元组——很可能是为了使多线程更简单。他们失败了。 =/咆哮=

似乎您只需要两个线程以乒乓方式打印 odd/even 数字。然后你可以利用ReentrantLock。有几种方法可以做到这一点。

我。锁

public static final ReentrantLock lock = new ReentrantLock();
public static final int LIMIT = 50;
public static int toPrint = 0;

public static void main(String[] args){
    Thread t1 = new Thread(() -> {
        while (true){
            try {
                lock.lock();
                if(toPrint > LIMIT) break;
                else if(toPrint % 2 == 0) {
                    System.out.println(toPrint++);
                }
            } finally {
                lock.unlock();
            }
        }
    });

    Thread t2 = new Thread(() -> {
        while (true) {
            try {
                lock.lock();
                if (toPrint > LIMIT) break;
                else if (toPrint % 2 == 1) {
                    System.out.println(toPrint++);
                }
            } finally {
                lock.unlock();
            }
        }
    });
    t1.start();
    t2.start();
}

二. Volatile(易碎,但有效)

public static final int LIMIT = 50;
public static volatile int toPrint = 0;

public static void main(String[] args){
    Thread t1 = new Thread(() -> {
        while (true){
            int cur = toPrint;
            if(cur > LIMIT) break;
            else if(cur % 2 == 0){
                System.out.println(cur);
                toPrint = cur + 1;
            }
        }
    });

    Thread t2 = new Thread(() -> {
        while (true) {
            int cur = toPrint;
            if(cur > LIMIT) break;
            else if(cur % 2 == 1){
                System.out.println(cur);
                toPrint = cur + 1;
            }
        }
    });
    t1.start();
    t2.start();
}
class EvenOddThread {
  public static void main (String [] args) {
  Runnable runnEven = new ThreadPrint (10);

  Thread t1 = new Thread (runnEven);
  Thread t2 = new Thread (runnEven);

  t1.start ();
  t2.start ();

  }
}

class ThreadPrint implements Runnable {
  private int maxPoint = 0;
  private int counter = 0;
  ThreadPrint (int max) {
    maxPoint = max;
  }

  @Override
  public void run () {
    while (counter <= maxPoint) {
      synchronized(this) {
        if (counter % 2 == 0) {

          System.out.println("By Thread" + Thread.currentThread().getName() +" :: "+ counter);
          counter ++;
          notify();
          try {
            wait();
          }
          catch (Exception e) {
            System.out.println(e);
          }
        }
        else if (counter % 2 != 0){
          System.out.println("By Thread" + Thread.currentThread().getName() +" :: "+ counter);
          counter ++;
          notify();
          try {
            wait();
          }
          catch (Exception e) {
            System.out.println(e);
          }
        }
      }
    }
  }
}

谢谢大家的回答,但我得到了帮助 here 弄清楚我应该如何更正我的代码。

现在,它按照我想要的方式工作。 :)