在CSDN看上看到有楼主提问顾客、厨师、服务员的问题,但描述不是很清楚。我自己梳理了一下,问题应该是这样的:用多线程模拟一个餐馆的运营流程:顾客就餐,服务员为其点菜,将菜单提交给厨师,厨师做好后通知服务员,服务员上菜,顾客用餐,主要是线程同步问题。

  想了一下问题的要点:
  1.因为服务员和厨师都为顾客服务,所以可以把顾客看做被服务员和厨师共享的资源。其实在现实中,顾客点的菜单亦可看做共享的资源 但这里简化了模型 只关心顾客来就餐, 而不关心顾客具体点了什么菜 ,所以无必要考虑菜单这些细节了
  2.服务员不能同时为同一个顾客服务
  3.多个厨师不能同时为做同一个顾客的菜
  4.服务员如何找到等待的顾客并为其上菜
  5.也是那位楼主的疑问,服务员如何同时监听顾客的需求和厨师的通知
  我是用java考虑的 感觉相对会简单一些 对以上的要点的解决思路如下:
  1.定义服务员、顾客、厨师、餐馆4个类,顾客实例数目是不固定的,服务员、厨师则是固定的,4个类别的实例的行为分别用4类线程描述,如:顾客到来、点餐、就餐、离开,等候;服务员服务、上菜;厨师做菜,通知;
  2.将顾客(菜单)看做共享资源 用阻塞队列去同步服务员服务行为
  3.仍将顾客(菜单)看做共享资源 资源由服务员投放 厨师取 资源保持提交顺序 考虑用同步队列去同步
  4.用map记录每个顾客实例作为对应线程的锁监视器,当服务员上菜时从map中找到对应的顾客对象 唤醒其监视器上的等待的线程
  5.可使顾客的需求和厨师的通知指向同一阻塞队列,即服务员监听同一阻塞队列,有个问题是当阻塞队列设置过小,而顾客需求来得太快导致厨师的通知无法投放时,会造成死锁,但是考虑下现实情况,当客源数量超过餐馆容量时总要顾客总要排队,所以我考虑阻塞队列设置对餐馆容量的2倍并实现顾客排队即可。
  梳理思路:
  1.设计服务员、顾客、厨师、餐馆4个类
  2.设计服务员、顾客、厨师、餐馆4类线程
  3.设计两个阻塞队列,其中一个同步顾客线程及厨师线程对服务员线程的通讯,另外一个同步服务员线程与厨师线程通讯,而且顾客线程产生顾客实例作为共享资源
  4.实现顾客排队及顾客等待被唤醒就餐

  <实现如下 仅是个人观点 如有不足和更好的建议 欢迎提出>



package com.java5.learning.concurrent;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
/**
 * 餐馆
 * @author zengjf
 *
*/
public class Restaurent {

private int serverAmount;
private int cookerAmount;
private int seats;//餐馆座位
    private BlockingQueue<Client> orderQueue;//服务员任务队列 包括招待顾客和上菜
    private BlockingQueue<Client> foodQueue;//厨子任务队列
    private ConcurrentMap<Integer, Client> clientWaitingPool;//等待的顾客
    
public Restaurent(int serverAmount,int cookerAmount,int seats){
this.serverAmount = serverAmount;
this.cookerAmount = cookerAmount;
this.seats = seats;
this.orderQueue = new ArrayBlockingQueue(seats*2);
this.foodQueue = new SynchronousQueue<Client>();
this.clientWaitingPool = new ConcurrentHashMap<Integer, Client>();
    }

public static void main(String[] args) throws Exception{
        Restaurent restaurent = new Restaurent(3,2,5);
        restaurent.doBusiness();
    }
/**
     * 餐馆运营
     * @throws Exception
*/
public void doBusiness() throws Exception{
        serverBehaviour();
        cookerBehavior();
        Thread.sleep(1000);
        clientBehaviour();
    }
/**
     * 模拟厨子执行任务
*/
private void cookerBehavior() {
        ExecutorService cookerExecutor = Executors.newFixedThreadPool(cookerAmount);

for (int i = 0; i < cookerAmount; i++) {
            cookerExecutor.execute(new Runnable() {
public void run() {
                    Employee cooker = EmployeeFactory.getEmployee("Cooker");
                    Client client;
while(true) {
try {
                            client = foodQueue.take();
                            cooker.serve(cooker + "为" + client +"做菜..");
                            Thread.sleep(new Random().nextInt(6)*1000);
                            client.setFoodPrepared(true);
                            orderQueue.put(client);
                            cooker.serve(cooker + "通知:" + client + "的菜做好了!");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
        cookerExecutor.shutdown();
    }
/**
     * 模拟服务员执行任务
*/
private void serverBehaviour() {
        ExecutorService serverExecutor = Executors.newFixedThreadPool(serverAmount);

for (int i = 0; i < serverAmount; i++) {
            serverExecutor.execute(new Runnable() {
public void run() {
                    Employee server = EmployeeFactory.getEmployee("Server");
                    Client client;
                    Client clientWaited;
while(true){
try {
                            client = orderQueue.take();
if (!client.isFoodPrepared()) {    
                                server.serve(server + "正接待" + client + "..");
                                Thread.sleep(new Random().nextInt(5)*1000);
                                server.serve(server + "为" + client + "提交菜单..");
                                foodQueue.put(client);
                            } else {
                                server.serve(server + "为" + client + "上菜..");
                                Thread.sleep(new Random().nextInt(3)*1000);
synchronized (Client.class) {
                                    clientWaited = clientWaitingPool.get(client
                                            .getSeq());
                                }
synchronized (clientWaited) {
                                    clientWaited.notify();
                                }
                                server.serve(server + "为" + client + "上菜完毕..");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
        serverExecutor.shutdown();
    }

/**
     * 生产顾客并模拟顾客行为
*/
private void clientBehaviour() {
        ExecutorService clientExecutor = Executors.newCachedThreadPool();
for (int i = 0; i <20; i++) {
            clientExecutor.execute(new Runnable() {
public void run() {
                    Client client;
try {
                        Thread.sleep(new Random().nextInt(10)*1000);

synchronized (Client.class) {
                            client = ClientFactory.newClient();
                            client.come();
while(clientWaitingPool.size() >= seats){
                                client.waiting();
                                Client.class.wait();
                                client.enter();
                            }

                            orderQueue.put(client);
                            clientWaitingPool.put(client.getSeq(),client);
                        }

synchronized (client) {
                            client.wait();
                        }

                        client.eat();
                        Thread.sleep(new Random().nextInt(10)*1000);
                        client.leave();

synchronized (Client.class) {                
                            clientWaitingPool.remove(client.getSeq());
                            Client.class.notify();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }    
                }
            });    
        }
        clientExecutor.shutdown();
    }


}
/**
 * 工厂:产生顾客
 * @author zengjf
 *
*/
class ClientFactory{
public static int order = 0;

public static Client newClient(){
return new Client(++order);
    }
}
/**
 * 顾客类
 * @author zengjf
 *
*/
class Client{
int seq;
boolean preparedTag;
public Client(int seq){
this.seq = seq;
this.preparedTag = false;
    }
    @Override
public String toString() {
return seq+"号客人";
    }
public int getSeq(){
return seq;
    }
public boolean isFoodPrepared(){
return preparedTag;
    }
public void setFoodPrepared(boolean tag){
        preparedTag = tag;
    }

public void come(){
        System.out.println(this + "到来..");
    }
public void eat(){
        System.out.println(this + "用餐..");
    }
public void leave(){
        System.out.println(this + "离开..");
    }
public void waiting(){
        System.out.println("客满," + this + "在等候..");
    }
public void enter(){
        System.out.println(this + "进入..");
    }
}
/**
 * 工厂:产生雇员
 * @author zengjf
 *
*/
class EmployeeFactory{
private static char num = 'A';
public static String genJobNumber(){
return  (char)(num++) + "";
    }

public static Employee getEmployee(String type){
if(type.equals("Server")){
return new Server(genJobNumber());
        }else{
return new Cooker(genJobNumber());
        }
    }
}

interface Employee{
    String getJobNumber();
void serve(String content);
}
/**
 * 服务员
 * @author zengjf
 *
*/
class Server implements Employee{
    String jobNumber;
public Server(String jobNumber){
this.jobNumber = jobNumber;
    }
    @Override
public String toString() {
return "服务员["+jobNumber+"]";
    }

public String getJobNumber(){
return jobNumber;
    }
public void serve(String content){
        System.out.println(content);
    }
}
/**
 * 厨子
 * @author zengjf
 *
*/
class Cooker implements Employee{
    String jobNumber;
public Cooker(String jobNumber){
this.jobNumber = jobNumber;
    }
    @Override
public String toString() {
return "厨子["+jobNumber+"]";
    }

public String getJobNumber(){
return jobNumber;
    }

public void serve(String content){
        System.out.println(content);
    }

}



有一问题,后来看文档解决了:java5的ConcurrentHashMap的更新操作是线程安全的,但get操作是线程不安全的,亦即多线程操作ConcurrentHashMap的话,get会引起NullPoint异常或数据不同步问题,所以要自行加锁