Java多线程中等待唤醒机制, 资源中的同步函数中添加 else 代码块时输出异常?

最近在学习java多线程中的等待唤醒机制, 如果操作资源的同步函数中添加了else代码块, 输出就会变得异常, 代码如下

// 资源
class Resource {
    private String name;

    private String sex;

    private boolean isExists = false; // 是否已有值

    public synchronized void set(String name, String sex) {
        if(isExists) {
            try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
        } else {  // 这里和 print() 方法中 如果不加else, 输出就是mike 和 丽丽 间隔输出, 如果添加, 就会有很多不间隔, 输出一大串丽丽或者mike 
            this.name = name;
            this.sex = sex;
            isExists = true;
            this.notify();
        }
    }

    public synchronized void print() {
        if(!isExists) {
            try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
        } else { // 如果不加else, 输出就是mike 和 丽丽 间隔输出, 如果添加, 就会有很多不间隔, 输出一大串丽丽或者mike
            System.out.println(this.name + "." + this.sex);
            isExists = false;
            this.notify();
        }
    }
}

// 赋值
class Input implements Runnable{

    private final Resource r;

    Input(Resource r) {
        this.r = r;
    }

    boolean flag = false; // 模拟赋值切换的

    @Override
    public void run() {
        for(;;) {
            if (flag) {
                r.set("mike", "man");
            } else {
                r.set("丽丽", "女女");
            }
            flag = !flag;
        }
    }
}

// 取值
class Output implements Runnable {

    private final Resource r;

    Output(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        for(;;) {
            r.print();
        }
    }
}

public class ResourceDemo {
    public static void main(String[] args) {

        Resource r = new Resource();

        Input in = new Input(r);
        Output out = new Output(r);

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);

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

正常输出结果: (mike和丽丽间隔输出)
丽丽.女女
mike.man
丽丽.女女
mike.man
丽丽.女女

不正常输出结果(无间隔输出):
mike.man
mike.man
mike.man
mike.man
mike.man
丽丽.女女
丽丽.女女

把this.notify();改为this.notifyAll();试试。

public synchronized void set(String name, String sex) {
while(isExists) {
try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
}
this.name = name;
this.sex = sex;
isExists = true;
this.notify();

}

public synchronized void print() {
   while(!isExists) {
        try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
    } 
        System.out.println(this.name + "." + this.sex);
        isExists = false;
        this.notify();
  
}

应该把if修改为while,因为线程执行顺序不固定

感觉写的有问题哈,输入与输出里的同步控制块中的条件没设置好,因为输入代表初始化值,输出代表把输入的消费了。所以需要等待输入去初始化值,如果输入有值了,需要唤醒输出去打印。
可以参考以下以下代码:

package jin.li.yun.com.common.test;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

// 资源
class Resource {
  private String name;
  private String sex;

  public synchronized void set(String name, String sex) {
    this.name = name;
    this.sex = sex;
  }

  public void print() {
    System.out.println(this.name + "." + this.sex);
  }
}
// 赋值
class Input implements Runnable {
  private final Resource r;
  private Queue<Resource> queue;
  private boolean flag = false;

  Input(Resource r, Queue<Resource> queue) {
    this.r = r;
    this.queue = queue;
  }

  @Override
  public void run() {
    while (true) {
      synchronized (queue) {
        while (queue.size() > 0) {
          try {
            //  System.out.println("Queue is Full");
            queue.wait();
          } catch (InterruptedException ie) {
            ie.printStackTrace();
          }
        }
        if (flag) {
          r.set("mike", "man");
        } else {
          r.set("丽丽", "女女");
        }
        this.flag = !flag;
        queue.add(r);
        queue.notify();
      }
    }
  }
}
// 取值
class Output implements Runnable {
  private final Resource r;
  private Queue<Resource> queue;

  Output(Resource r, Queue<Resource> queue) {
    this.r = r;
    this.queue = queue;
  }

  @Override
  public void run() {
    while (true) {
      synchronized (queue) {
        while (queue.isEmpty()) {
          // System.out.println("Queue is Empty");
          try {
            queue.wait();
          } catch (InterruptedException ie) {
            ie.printStackTrace();
          }
        }
        queue.remove();
        r.print();
        queue.notify();
      }
    }
  }
}

public class ResourceDemo {
  public static void main(String[] args) {
    Queue<Resource> queue = new LinkedList<>();
    Resource r = new Resource();
    Input in = new Input(r, queue);
    Output out = new Output(r, queue);
    Thread t1 = new Thread(in);
    Thread t2 = new Thread(out);
    t1.start();
    t2.start();
  }
}

运行结果:
img