生产者与消费者

98 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

大家好,我是尚影嫣🌷,一名Java后端程序媛。如果您喜欢我的文章,欢迎点赞➕关注❤️,让我们一起成为更好的我们~🥰

所谓生产者消费者模式,即多个线程进行生产,同时多个线程进行消费。两种角色通过内存缓冲区进行通信,解决了代码之间的耦合程度。

信号灯法

使用Object的wait() / notify()方法:

wait() / nofity()方法是基类Object的两个方法,所以所有的Java类都拥有这两个方法,我们就可以为任何对象实现同步机制。

  • wait():当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。

  • notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

package yanf.thread;

public class ProducerAndConsumer {
    public static void main(String[] args) {
        Food f = new Food();
        new Cooker(f).start();
        new Waiter(f).start();
    }

    // 生产者-厨师
    static class Cooker extends Thread {
        private Food f;

        public Cooker(Food f) {
            this.f = f;
        }

        // 做菜
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    f.setNameAndTaste("小米南瓜粥", "清香~");
                } else {
                    f.setNameAndTaste("奶油小蛋糕", "甜甜腻腻!");
                }
            }
        }
    }

    // 消费者-服务员
    static class Waiter extends Thread {
        private Food f;

        public Waiter(Food f) {
            this.f = f;
        }

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                try {
                    // 休眠0.1s
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 端菜
                f.get();
            }
        }
    }

    // 食物
    static class Food {
        private String name;
        private String taste;
        // true 表示可以生产
        private boolean flag = true;

        public synchronized void setNameAndTaste(String name, String taste) {
            if (flag) {
                this.name = name;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = taste;
                flag = false;
                // 唤醒其他休息的线程
                this.notifyAll();
                // 休息一下
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public synchronized void get() {
            if (!flag) {
                System.out.println("服务员端走的菜的名称是:" + name + ",味道是:" + taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

运行结果如下:

image.png