多线程、线程通信案列

在抖音刷到一款小游戏,感觉挺有意思,多线程的,正好用它练一练多线程。不对或者不完善的地方请多多指教。

游戏叫做开心餐厅,大体就是:
客人陆陆续续的光临餐厅,餐厅里有空位就进入坐下点餐,没座位就排队等候,点餐后产生订单列表,厨师按点餐顺序为客人做食物,做好了送至该食物客人的餐桌,回去继续做菜,客人吃完付钱离开,座位空出,等待的客人进入座位,如此循环。厨师,座椅可以临时增加,本次设计固定3个厨师,4把椅子。

核心代码,shop类

package com.chinasoft.springboot.entities;

import lombok.Data;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 15075
 * @date 2021/4/7 08:50:40
 * @discription
 */
@Data
public class Shop {

    /**
     * 菜单初始化
     */
    Menu menu = initMenu();

    /**
    等待制作的菜品
     */
    List<Food> foods = new ArrayList<>();

    /**
     * 今日订单数计数器
     */
    Integer foodSize = 0;

    /**排队中的顾客*/
    List<Customer> customers = new LinkedList<>();

    /**全部的顾客*/
    List<Customer> allCustomers = new LinkedList<>();

    /**桌椅*/
    List<Table> tables = getTables();

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    /**
     * 模拟餐厅座椅数据
     * @return
     */
    private List<Table> getTables() {
        Table table1 = new Table();
        table1.setTid(1);
        Chair chai1 = new Chair();
        chai1.setCid(1);
        Chair chai2 = new Chair();
        chai2.setCid(2);

        List<Chair> table1Char = new ArrayList<>() ;
        table1Char.add(chai1);
        table1Char.add(chai2);
        table1.setChairs(table1Char);

        Table table2 = new Table();
        table2.setTid(2);
        Chair chai3 = new Chair();
        chai3.setCid(3);
        Chair chai4 = new Chair();
        chai4.setCid(4);

        List<Chair> table2Char = new ArrayList<>() ;
        table2Char.add(chai3);
        table2Char.add(chai4);
        table2.setChairs(table2Char);

        List<Table> tables = new ArrayList<>();
        tables.add(table1);
        tables.add(table2);

        return  tables;
    }

    /**
     * 菜单初始化
     * @return
     */
    private Menu initMenu() {
        Menu menu = new Menu();
        List<Food> cai = new ArrayList<>();
        Food food1 = new Food();
        food1.setFoodId(1);
        food1.setFoodName("意大利面1");

        Food food2 = new Food();
        food2.setFoodId(2);
        food2.setFoodName("小鸡炖蘑菇2");

        Food food3 = new Food();
        food3.setFoodId(3);
        food3.setFoodName("黄焖鸡3");

        Food food4 = new Food();
        food4.setFoodId(4);
        food4.setFoodName("咖喱土豆4");

        cai.add(food1);
        cai.add(food2);
        cai.add(food3);
        cai.add(food4);
        menu.setMenu(cai);

        return menu;
    }

    /**
     * 模拟餐厅进入客人
     */
    public void addCustomer(){
        try {
            //平均每2秒招揽一位顾客
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Customer customer = new Customer();
        customer.setCusId(allCustomers.size()+1);
        customer.setCusName("顾客"+(allCustomers.size()+1));

        lock.lock();
        try {
            customers.add(customer);
            allCustomers.add(customer);
            //客人光临,唤醒椅子线程招待客人入座
            condition.signal();
        } finally {
            lock.unlock();
        }

        System.out.println(customer.getCusName() + "光顾了本店");

    }

    /**
     * 椅子线程监控椅子和顾客状态进行为客人分配座位
     * @throws InterruptedException
     */
    public void paiChair() throws InterruptedException {
        lock.lock();
        try {
            //有无空座标识
            boolean isEmpty =false;
            out:
            for (Table table:tables) {
                for (Chair chair : table.getChairs()) {

                    //判断当前有无空座
                    if (chair.getCustomer() == null) {
                        isEmpty =true;
                        break out;
                    }
                }
            }

            if (customers.size()<=0 || !isEmpty ){
                //没有顾客或者没有空座,进入等待
                condition.await();
            }
            //椅子上无顾客就请进等待中的顾客
            else {
                outer:
                for (Table table:tables)  {
                    for (Chair chair: table.getChairs()) {

                        //椅子上无顾客就放进等待中的顾客
                        if (chair.getCustomer() == null){

                            Customer customer = customers.get(0);

                            //等待的第一个入座
                            chair.setCustomer(customer);

                            System.out.println(customer.getCusName()+"坐在了"
                                    +table.getTid()+ "号桌的" + chair.getCid()+"号椅子上");

                            //客人从等待队列中移除
                            customers.remove(0);

                            Random r = new Random();
                            Integer ran1 = r.nextInt(menu.getMenu().size());

                            //模拟顾客点菜,随机生成一份点菜单
                            Food food = new Food();
                            Food menuFood = menu.getMenu().get(ran1);
                            food.setFoodNo(++foodSize);
                            food.setFoodName(menuFood.getFoodName());
                            food.setFoodId(menuFood.getFoodId());
                            food.setByCustomer(customer);

                            foods.add(food);
                            System.out.println("顾客"+customer.getCusName()+"点了" + food.getFoodName());

                            //客人点菜,唤醒厨师线程做菜
                            condition.signal();

                            break outer;
                        }
                    }
                }
            }
        }finally {
            lock.unlock();
        }
    }

    /**
     * 模拟厨师做菜
     */
    public void zuoCai(){
        lock.lock();
        try {
            //没有等待制作的菜品时进入等待
            if (foods.size()==0){
                try {
                    condition.await();
                } finally {
                    lock.unlock();
                }

            }else {

                Food food = foods.get(0);
                try {
                    foods.remove(0);
                    System.out.println(Thread.currentThread().getName()+"取走了"+food.getByCustomer().getCusName()+"所点的菜品单:"+food.getFoodName());
                    System.out.println("剩余点餐单:"+foods);
                } finally {
                    lock.unlock();
                }

                //模拟做菜时间
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+"用了3秒做好了"+food.getByCustomer().getCusName()+"的食物"+food.getFoodName());

                //模拟传菜时间(这里传菜也是由厨师负责)
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+"用了3秒将食物"+food.getFoodName() + "送到了顾客手中");

                //为点了该菜品的顾客开起吃饭线程
                new Thread(() -> {
                    try {
                        //模拟吃饭时间
                        Thread.sleep(3000);
                        outer:
                        for (Table table:tables) {
                            for (Chair chair : table.getChairs()) {
                                if (!ObjectUtils.isEmpty(chair.getCustomer()) && food.getByCustomer().getCusId().equals(chair.getCustomer().getCusId())){
                                    chair.setCustomer(null);
                                    System.out.println(food.getByCustomer().getCusName()+"吃完了" + food.getFoodName());
                                    break outer;
                                }

                            }
                        }
                        lock.lock();
                        try {
                            //客人吃完饭离开,唤醒椅子线程接待客人入座
                            condition.signal();
                        } finally {
                            lock.unlock();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();

                //模拟传菜回到厨房时间
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName()+"回到了厨房继续工作");

            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

    }
}

三个线程类
ChairThread 椅子线程,负责将等待的客人接待入座,点餐

public class ChairThread implements Runnable{
    Shop shop;
    public ChairThread(Shop shop){
        this.shop=shop;
    }
    @SneakyThrows
    @Override
    public void run() {
        while(true){
            shop.paiChair();
        }
    }
}

ChefThread 厨师线程负责将客人点的餐制作好,并送至客人座位(告知可以用餐了)

public class ChefThread implements Runnable{
    private Shop shop;
    public ChefThread(Shop shop){
        this.shop = shop;
    }

    @Override
    public void run() {
        while (true){
            shop.zuoCai();
        }
    }
}

MakeCustomerThread 这是一个模拟源源不断的进入客人的线程

public class MakeCustomerThread implements Runnable{
    private Shop shop;

    public MakeCustomerThread (Shop shop){
        this.shop = shop;
    }

    @Override
    public void run() {
        //招揽顾客
        while (true){
            shop.addCustomer();
        }
    }
}

main函数 此处模拟店内有三个厨师

public static void main(String[] args) {
        Shop shop = new Shop();

        MakeCustomerThread makeCustomer = new MakeCustomerThread(shop);
        Thread makeCustomerThread =new Thread(makeCustomer);
        makeCustomerThread.start();

        ChairThread ChairThread = new ChairThread(shop);
        Thread chairThread =new Thread(ChairThread);
        chairThread.start();

        ChefThread makeChef = new ChefThread(shop);
        Thread makeChefThread =new Thread(makeChef);
        makeChefThread.setName("厨师1");
        makeChefThread.start();

        Thread makeChefThread2 =new Thread(makeChef);
        makeChefThread2.setName("厨师2");
        makeChefThread2.start();

        Thread makeChefThread3 =new Thread(makeChef);
        makeChefThread3.setName("厨师3");
        makeChefThread3.start();
}

其他无关紧要的类忽略,请大神们指点是否正确,是否需要改进。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值