多线程_多个生产者多个消费者问题
多线程中多个生产者多个消费者问题
还是之前的问题:厨师负责做菜,服务员负责给客人上菜,厨师做好的菜放在工作台上,服务员从工作台上取菜品,但是这次的厨师和服务员都有多个.
首先创建出多个厨师和多个服务员是很简单的,为了方便,我们给线程重命名一下,做一个标记,在后面方便进行观察.
public class TestCommunicate {
public static void main(String[] args) {
//创建工作台
WorkBench w= new WorkBench();
//创建厨师
Cook c1 = new Cook(w,"厨师1");
Cook c2 = new Cook(w,"厨师2");
Waiter t1 = new Waiter(w,"服务员1");
Waiter t2 = new Waiter(w,"服务员2");
Waiter t3 = new Waiter(w,"服务员3");
//启动线程
c1.start();
c2.start();
t1.start();
t2.start();
t3.start();
}
}
//因为要保证Cook和Waiter使用的是同一个WorkBench的对象,我们用传参数的方式
class Cook extends Thread{
//要使用WorkBench类中的方法:
//(1)使用静态
//(2)传递对象
private WorkBench w;
public Cook(WorkBench w,String name) {
super(name);
this.w =w;
}
public void run() {
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
w.put();
}
}
}
class Waiter extends Thread{
private WorkBench w;
public Waiter(WorkBench w,String name) {
super(name);
this.w= w;
}
public void run() {
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
w.take();
}
}
}
下面是工作台的功能设计,我们要解决的问题是:
(1)厨师和服务员都有多个,我们在厨师做菜和服务员取菜时,怎么能让线程在数据处理的时候不发生错误.
(2)notify()方法唤醒线程,是随机唤醒的,要防止线程的循环等待.
class WorkBench{
//假设最多放10个菜
private static final int MAX_VALUE =10;
//num记录放的菜的数量
private int num;
//在多个厨师多个服务员的条件下,如果;
//(1)厨师还没有做菜,服务员1wait服务员2wait服务员3wait
//(2)厨师做了一份菜,因为notify是随机唤醒一个线程,我们假设唤醒的是服务员1,那么num==1,执行之后还有一个notify,这时候
//虽然num==0,服务员2还是被唤醒了,结果执行了后面的num--和notify并唤醒了服务员3
//这就会造成错误,我们需要在服务员1唤醒服务员2之后,再判断num的值,考虑是否执行num--的操作.因此将if改为while
public synchronized void take() {
//
while(num<=0) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
num--;
System.out.println("服务员"+Thread.currentThread().getName()+"拿走了一份菜剩余"+num);
this.notifyAll();
}
public synchronized void put() {
while(num>=MAX_VALUE) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
num++;
System.out.println("厨师"+Thread.currentThread().getName()+"又炒好了一份菜剩余"+num);
this.notifyAll();
}
}