public class Demo {

    /* 生产者步骤:
     * 1、判断桌子上是否有汉堡包
     * 2、如果有就等待,如果没有,就生产
     * 3、把生产的汉堡包放到桌子上
     * 4、唤醒消费者开吃
     * 
     * 消费者步骤:
     * 1、判断汉堡包剩余数量,如果没有了,跳出线程
     * 2、判断桌子上是否有汉堡包
     * 3、如果没有就等待
     * 4、如果有就吃,
     * 5、吃完后桌子上的汉堡包没有了,状态改为false,然后叫醒厨师继续做汉堡包
     *   汉堡包总量减1
     */
    public static void main(String[] args) {
        Desk desk = new Desk(true, 10);
        Foodie f = new Foodie(desk);
        Cookie c = new Cookie(desk);
        f.start();
        c.start();
    }

}
/**
 * 消费状态
 */
public class Desk {

    // 定义一个标记 flag
    // true表示桌子上有汉堡包,此时允许吃货Foodie(消费者线程)执行
    // false表示桌子上没有汉堡包,此时允许厨师Cookie(生产者线程)执行
    // public static boolean flag = false; 使用public static也可以,但是无法体现面向对象编程思想
    private boolean flag;

    // 汉堡包的总量
    // public static int count = 10;
    private int count;

    // 锁对象 (加final关键字是因为锁对象需要唯一,不能让别人去修改锁对象的地址值)
    // public static final Object lock = new Object();
    private final Object lock = new Object();

    public Desk() {}

    public Desk(boolean flag, int count) {
        this.flag = flag;
        this.count = count;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public Object getLock() {
        return lock;
    }

}
/**
 * 消费者线程
 */
public class Foodie extends Thread {

    private Desk desk;

    public Foodie(Desk desk) {
        this.desk = desk;
    }

    /*
     * 1、判断汉堡包剩余数量,如果没有了,跳出线程
     * 2、判断桌子上是否有汉堡包
     * 3、如果没有就等待
     * 4、如果有就吃,
     * 5、吃完后桌子上的汉堡包没有了,状态改为false,然后叫醒厨师继续做汉堡包
     *   汉堡包总量减1
     */
    @Override
    public void run() {
        while (true) {
            synchronized (desk.getLock()) {
                if (desk.getCount() == 0) {
                    System.out.println("今天吃了10个汉堡包了,不能再吃了!");
                    break;
                }
                if (desk.isFlag()) {
                    // 有,开吃
                    System.out.println("吃货把桌子上的汉堡包干掉!");
                    desk.setFlag(false);
                    // 使用什么对象当作锁,那么就必须用这个对象去调用等待和唤醒的方法
                    // notifyAll()叫醒这个锁上的所有线程,notify()随机叫醒单个线程
                    desk.getLock().notifyAll();
                    desk.setCount(desk.getCount() - 1);
                } else {
                    // 没有,等待
                    try {
                        desk.getLock().wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
/**
 * 生产者线程
 */
public class Cookie extends Thread {

    private Desk desk;

    public Cookie(Desk desk) {
        this.desk = desk;
    }

    /*
     * 1、判断桌子上是否有汉堡包
     * 2、如果有就等待,如果没有,就生产
     * 3、把生产的汉堡包放到桌子上
     * 4、唤醒消费者开吃
     */
    @Override
    public void run() {
        while (true) {
            synchronized (desk.getLock()) {
                if (desk.getCount() == 0) {
                    System.out.println("生产了10个汉堡包了,今天生产总数已达到,不用再生产了!");
                    break;
                }
                if (!desk.isFlag()) {
                    // 没有,生产
                    System.out.println("厨师生产了一个汉堡包!");
                    desk.setFlag(true);
                    desk.getLock().notifyAll();
                } else {
                    // 有,等待消费者吃
                    try {
                        desk.getLock().wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

}