[英]Java thread project weird behavior while increasing num of threads
我创建了一个用于研究目的的项目,该项目使用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();
}
}
}
}
两个问题:
Main.DONE_MEALS == 5
。 由于有其他厨师,它将从4跳到6。 相反,请检查Main.DONE_MEALS >= 5
。 Main.DONE_MEALS
的更新。 相反,请考虑使用private static final AtomicInteger
字段。 AtomicInteger
类是一个线程安全的整数实现,使其他线程能够以线程安全的方式查看它。 传统的解决方法是:
a)您不仅必须在写时使用锁(互斥锁),而且在阅读时也必须使用锁-否则它将无法正常工作。 试想一下,如果您同意一个信号以指示浴室是否忙碌,但有些人只是决定忽略它-则行不通!
b)在做某事之前,请检查条件。
一旦获得了锁,您就不会知道状态,因此您应该先检查一下它,然后再做一顿饭。 如果您首先检查是否已经做过5顿饭,而仅在没有5 done_meals <= 5
,那应该可以解决此问题,并且您应该只看到done_meals <= 5
(您应该查看代码的其他部分,因为它有类似的问题)。
就像其他人提到的那样,有一些更干净的方法可以编写此代码,但是IMO您的代码非常适合实践和理解,因此我会尝试这样做,而不是像AtomicInteger这样跳槽。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.