/*
* 生产者消费者 案例 (使用Lock 同步锁 方式,使用Condition完成线程之间的通信)
* */
public class TestProductorAndConsumerForLock {
public static void main(String[] args) {
WareHouse wareHouse = new WareHouse();
Productor pd1 = new Productor(wareHouse);
Consumer cs1 = new Consumer(wareHouse); new Thread(pd1, "消费者1").start();
new Thread(cs1, "生产者1").start();
// 若有多个 生产者消费者,可能会产生虚假唤醒(缺货了,多个生产线程等待,唤醒时,这些生产线程同时醒来,对数据进行操作,这种问题叫做虚假唤醒)
// 解决办法:wait方法 尽量 使用在循环中,被唤醒之后,再去判断是否符合条件(库存是否达到上限),不符合条件
// 继续等待(等待消费者去消费商品),直到 条件符合(库存有空闲)
new Thread(pd1, "消费者2").start();
new Thread(cs1, "生产者2").start();
}
} // 仓库
class WareHouse {
// 商品数量
private int products = 0;
private ReentrantLock lock = new ReentrantLock();
//使用 Condition 的前提是 使用 Lock 同步锁,Condition 实例 实质上被绑定到一个锁上
private Condition condition = lock.newCondition(); public void set() {
lock.lock();
try {
while (products >= 1) {
System.out.println("商品库存满了");
try {
// 如果商品满了,阻塞线程,等待消费者线程消费完成后唤醒,
condition.await(); //相当于(Object.awatit() 但是功能更强大)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("生产了商品,剩余库存" + ++products);
condition.signalAll(); //相当于 (Object.notifyAll,功能更强大)
} finally {
lock.unlock();
} } public void get() {
lock.lock();
try {
while (products <= 0) {
System.out.println("商品库存没了");
try {
// 如果商品没了,阻塞线程,等待生产者线程生产完成后唤醒,
condition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("消费了商品,剩余库存" + --products);
condition.signalAll();
} finally {
lock.unlock();
} }
} // 生产者
class Productor implements Runnable {
private WareHouse wareHouse; public Productor(WareHouse wareHouse) {
this.wareHouse = wareHouse;
} @Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
wareHouse.get();
}
} } // 消费者
class Consumer implements Runnable {
private WareHouse wareHouse; public Consumer(WareHouse wareHouse) {
this.wareHouse = wareHouse;
} @Override
public void run() {
for (int i = 0; i < 20; i++) { wareHouse.set();
}
} }