我创建了一个研究项目,该项目使用Threads模拟餐厅服务。有一个线程供厨师准备饭菜,还有一个线程供服务员提供饭菜。当我与1位厨师和5位侍者一起测试时,它工作正常。但是,当我增加厨师人数时,该程序将无限期运行。怎么了?这是代码:
主要班级
package restaurant;
import java.util.concurrent.Semaphore;
public class Main {
public static int MAX_NUM_MEALS = 5;
public static int OLDEST_MEAL = 0;
public static int NEWEST_MEAL = -1;
public static int DONE_MEALS = 0;
public static int NUM_OF_COOKS = 1;
public static int NUM_OF_WAITERS = 5;
public static Semaphore mutex = new Semaphore(1);
static Cook cookThreads[] = new Cook[NUM_OF_COOKS];
static Waiter waiterThreads[] = new Waiter[NUM_OF_WAITERS];
public static void main(String[] args) {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i] = new Cook(i);
cookThreads[i].start();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i] = new Waiter(i);
waiterThreads[i].start();
}
try {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i].join();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i].join();
}
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("All done");
}
}
库克阶级
package restaurant;
public class Cook extends Thread{
private int id;
public Cook(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Cook " + id + " is prepearing meal");
try {
Thread.sleep(1000);
Main.mutex.acquire();
Main.NEWEST_MEAL++;
Main.mutex.release();
Main.mutex.acquire();
Main.DONE_MEALS++;
Main.mutex.release();
System.out.println("Cook " + id + " has finished the meal");
if(Main.DONE_MEALS == 5) {
System.out.println("Cook " + id + " has finished his job");
break;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
班级服务员
package restaurant;
public class Waiter extends Thread{
private int id;
public Waiter(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Waiter " + id + " will check if there is any meal to serve");
if(Main.NEWEST_MEAL >= Main.OLDEST_MEAL) {
try {
Main.mutex.acquire();
Main.OLDEST_MEAL++;
Main.mutex.release();
System.out.println("Waiter " + id + " is picking up meal");
Thread.sleep(500);
System.out.println("Waiter " + id + " has delivered the meal to client");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(Main.DONE_MEALS == 5) {
System.out.println("Waiter " + id + " has finished his job");
break;
}
System.out.println("No meal to serve. Waiter " + id + " will come back later");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
答案 0 :(得分:0)
两个问题:
Main.DONE_MEALS == 5
。由于有其他厨师,它将从4跳到6。相反,请检查Main.DONE_MEALS >= 5
。Main.DONE_MEALS
的更新。而是考虑使用private static final AtomicInteger
字段。 AtomicInteger
类是一个线程安全的整数实现,使其他线程能够以线程安全的方式查看它。答案 1 :(得分:0)
传统解决方法是:
a)您不仅必须在写时使用锁(互斥锁),而且在阅读时也必须使用锁-否则它将无法正常工作。 试想一下,如果您同意一个信号以指示浴室是否忙碌,但有些人只是决定忽略它-则行不通!
b)在做某事之前检查一下状况。
一旦获得了锁,您就不会知道状态,因此您应该先检查一下它,然后再做一顿饭。如果您首先检查是否已经做过5顿饭,而只有5顿才做饭,那应该可以解决此问题,并且您应该只看到done_meals <= 5
(您应该查看代码的其他部分,因为不过,它也有类似的问题)。
就像其他人提到的那样,有一些更干净的方法可以编写此代码,但是IMO您的代码非常适合实践和理解,因此我会尝试这样做,而不是像AtomicInteger这样跳转。