认识多线程:等待唤醒机制

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/woailuo23/article/details/97612056
package com.pccc.pactera.juc01;

public class TestProducterAndConsumer {
	public static void main(String[] args) {
		Clerk clerk = new Clerk();
		Porductor p = new Porductor(clerk);
		Consumer c = new Consumer(clerk);
		new Thread(p, "生产者A").start();
		new Thread(c, "消费者B").start();
		new Thread(p, "生产者C").start();
		new Thread(c, "消费者D").start();
	}
}

/**
 * 店员类 有进货,售出 两个操作 等待唤醒机制
 * 
 * @author zhao
 * 
 */
class Clerk {
	private int product = 0;// 产品量初始值

	// 进货
	public synchronized void get() {
		while (product >= 1) {// 为了避免虚假唤醒问题 ,应该总是使用在循环中
			System.out.println("产品已满");
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + ":" + ++product);
		this.notifyAll();
	}

	// 售出
	public synchronized void sale() {
		while (product <= 0) {
			System.out.println("缺货");
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName() + ":" + --product);
		this.notifyAll();
	}

}

/**
 * 生产者
 * 
 * @author zhao
 * 
 */
class Porductor implements Runnable {
	private Clerk clerk;

	public Porductor(Clerk clerk) {// 构造器
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			clerk.get();// 进货
		}
	}
}

/**
 * 消费者
 * 
 * @author zhao
 * 
 */
class Consumer implements Runnable {
	private Clerk clerk;

	public Consumer(Clerk clerk) {
		this.clerk = clerk;
	}

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			clerk.sale();// 售出操作
		}
	}
}

 首先走读一下上边代码,声明一个店员类,有进货和出货两个操作,创建消费者类和生产者类实现消费和生产操作,设置循环次数,

注意点1:若使用if...else会出现虚假唤醒问题,查看wait的JDK API可知

对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
     }
 

此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。

所以此处使用while ;

注意点2:在进货和售出两个方法中,执行++product和唤醒所有线程,考虑生产者和消费者线程可能会出现不同步,因为网络或应用的延迟问题,会出现当消费者循环次数为2时,生产者循环次数为1,导致主方法运行时,有线程处于等待状态,无法结束运行。

猜你喜欢

转载自blog.csdn.net/woailuo23/article/details/97612056