代码
package com.example.KFC;
public class Cooker extends Thread {
public void run() {
while (true) {
synchronized (Desk.lock) {
if (Desk.maxCount == 0) {
break;
} else {
if (!Desk.flag) {
System.out.println("Cooker makes a hamburger");
Desk.flag = true;
Desk.lock.notifyAll();
} else {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
}
package com.example.KFC;
public class Foodie extends Thread {
public void run() {
while (true) {
synchronized (Desk.lock) {
if (Desk.maxCount == 0) {
System.out.println("Foodie is out of food");
break;
} else {
if (Desk.flag) {
Desk.maxCount--;
System.out.println("Foodie eats a hamburger and have " + Desk.maxCount + " hamburger to eat left");
Desk.flag = false;
Desk.lock.notifyAll();
} else {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
}
package com.example.KFC;
public class Desk {
public static boolean flag = false;
public static int maxCount = 10;
static Object lock = new Object();
}
package com.example.KFC;
public class Demo {
public static void main(String[] args) {
Foodie f = new Foodie();
Cooker c = new Cooker();
f.start();
c.start();
}
}
背景介绍
这四个程序是一个简单的生产者消费者模型的实现,用于模拟厨师(生产者)制作汉堡,食客(消费者)吃汉堡的过程。
Desk.java:这是一个共享资源类,包含了一个标志位flag,一个最大计数器maxCount和一个锁对象lock。flag用于标记是否有汉堡可供食客吃,maxCount用于记录还剩下多少汉堡,lock用于同步厨师和食客的行为。
Cooker.java:这是厨师类,继承了Thread类。在其run方法中,厨师会不断地制作汉堡,直到maxCount为0。如果flag为false,表示没有汉堡,厨师就会制作一个汉堡,并将flag设为true,然后唤醒所有在lock上等待的线程(即食客)。如果flag为true,表示有汉堡,厨师就会在lock上等待。
Foodie.java:这是食客类,也继承了Thread类。在其run方法中,食客会不断地吃汉堡,直到maxCount为0。如果flag为true,表示有汉堡,食客就会吃掉一个汉堡,并将flag设为false,然后唤醒所有在lock上等待的线程(即厨师)。如果flag为false,表示没有汉堡,食客就会在lock上等待。
Demo.java:这是主程序类,创建了一个厨师线程和一个食客线程,并启动它们。
这四个程序共同模拟了一个生产者消费者问题的解决方案,通过wait和notifyAll方法以及同步块来保证厨师和食客的行为的同步性,避免了资源的浪费和冲突。
流程解读
一个“锁”上的多个线程在同一时间只能有一个处于运行态;
在本案例中,吃货和厨师在start后进入就绪态,随后吃货进入运行态,厨师在就绪态“排队”,随后吃货在run中notifyAll,随后他通过wait进入等待态,在就绪态准备的厨师进入运行态,执行厨师进程的run,在对Desk执行完方法后notiFyAll唤醒吃货使其进入就绪态排队,随后厨师通过wait进入等待态,在就绪态准备的吃货进入运行态,如此周而复始,一直到共享数据结束。