最近在学习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();
}
}
运行结果: