多线程的等待唤醒机制之消费者和生产者模式


/**
* 等待唤醒之生产者和消费者模型
* 生成者: 创建和添加数据的线程
* 消费者: 销毁和删除数据的线程
* 问题1: 生成者生成数据过快, 消费者消费数据相对慢,不接收数据了, 会造成数据丢失
* 问题2: 消费者消费数据过快, 生成者生成数据相对慢,不发送数据了, 会造成数据被重复读取
* 总结 : 生产数据过快会造成数据丢失
* 生成数据过慢会造成数据被重复读取
*
*
* wait()和notifyAll()用法:
* 1. 必须是同一个对象的wait()和和notifyAll()方法
* 2. wait()和notifyAll()必须用在同步方法或同步代码块中
* 3. wait()存在中断和虚假唤醒(多个生成者和消费者线程等待时会出现虚假唤醒)问题,
* 虚假唤醒: 多个消费者线程等待时, 唤醒后, 都会接着执行同步方法中未完成的代码
* 解决办法 : wait()必须放在while循环中 , 即在线程被唤醒后 先继续进行判断, 不符合条件就继续等待`
*/

public class ProductorAndConsumerTest {

public static void main(String[] args) {
Clerk clerk = new Clerk();

Productor productor = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(productor, "生成者A").start();
new Thread(consumer, "消费者B").start();
new Thread(productor, "生成者C").start();
new Thread(consumer, "消费者D").start();
}

}

// 店员 持有产品
class Clerk{
private int product = 0;

public synchronized void getPro() throws InterruptedException {
// wait()必须处在while循环体中
while (product >= 1){
System.out.println("产品已满!");
this.wait();
}

System.out.println(Thread.currentThread().getName() + "生产了产品" + (++product));
this.notifyAll();

}

public synchronized void sale() throws InterruptedException {
// wait()必须处在while循环体中
while (product <= 0){
System.out.println(Thread.currentThread().getName() + "缺货!");

this.wait();
}

System.out.println(Thread.currentThread().getName() + "消费了产品" + (--product));
this.notifyAll();

}
}

//生产者线程
class Productor implements Runnable{
private Clerk clerk;

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

@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
clerk.getPro();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

//消费者线程
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++) {
try {
clerk.sale();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

猜你喜欢

转载自www.cnblogs.com/huangleshu/p/10030122.html