问题描述
生产者(Productor)将产品交给店员(Clerk),而消费者(Consumer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
wait()/notify()/notifyall()方法
package com.java.ht;
public class Demo1 {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p = new Producer(clerk);
Consumer c = new Consumer(clerk);
new Thread(p, "生产者A").start();
new Thread(p, "生产者B").start();
new Thread(c, "消费者A").start();
new Thread(c, "消费者B").start();
}
}
class Clerk{
private int product = 0;
public synchronized void getProduct(){
while(product >= 20){
System.out.println("货架已满");
try {
//如果货架满了,则需要让该线程等待,生产者停止生产
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + ++product);
//卖出货物后,需要唤醒全部线程,其他消费者可以继续消费,生产者继续生产
notifyAll();
}
public synchronized void sellProduct(){
while (product <= 0){
System.out.println("货架上缺货");
try {
//如果没有货物了,消费者需要等待
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + --product);
//消费完需要唤醒其他线程,生产需要生产,其他消费者消费
notifyAll();
}
}
class Producer implements Runnable{
private Clerk clerk;
public Producer(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.getProduct();
}
}
}
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.sellProduct();
}
}
}
- 方法最后一定要记得唤醒线程
- wait()一定要放在循环体里面,不然可能会出现虚假唤醒
Lcok和Condition
package com.java.ht;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo2 {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p = new Producer(clerk);
Consumer c = new Consumer(clerk);
new Thread(p, "生产者A").start();
new Thread(p, "生产者B").start();
new Thread(c, "消费者A").start();
new Thread(c, "消费者B").start();
}
}
class Clerk{
private int product = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void getProduct(){
lock.lock();
try {
if(product >= 20){
//货架已满,停止生产
System.out.println("货架已满");
condition.await();
} else {
System.out.println(Thread.currentThread().getName() + ":" + ++product);
//生产了货物,唤醒其他线程
condition.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void sellProduct(){
lock.lock();
try {
if(product <= 0){
//货架上没有货物,需要让消费者等待
condition.await();
} else {
System.out.println(Thread.currentThread().getName() + ":" + --product);
//消费者消费完成,唤醒其他线程,消费者可以继续消费,生产者可以继续生产
condition.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Clerk clerk;
public Producer1(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.getProduct();
}
}
}
class Consumer implements Runnable{
private Clerk clerk;
public Consumer1(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sellProduct();
}
}
}
- 记得最后使用unlock()解锁
- Condition是Lock里面的newCondition()产生的
- await(),signal(),signalAll()方法和Object类中的wait(),notify(),notifyAll()一样
- 与上一种方法比,这种的效率更高