笔试题:请写出一个消费者生产者模型

简介: “请写出一个生产者消费者模型。一个生产者,一个消费者,生产者生产一个,消费者消费一个”。

“请写出一个生产者消费者模型。一个生产者,一个消费者,生产者生产一个,消费者消费一个”。

这是一个典型的多线程面试题,考验对锁和多线程对运用。要想实现,有两种常见模式。一种是通过wait() / notify(),另一种是通过 ReentrantLock 的 condition。

wait()和notify()实现

Object的wait() / notify()是第一种实现方式。

这里有必要提一下Thread.sleep()和Object.wait()的区别。

sleep和wait区别

1、Thread.sleep()不会导致锁行为的改变,如果当前线程是拥有锁的,那么Thread.sleep()不会让线程释放锁。如果能够帮助你记忆的话,可以简单认为和锁相关的方法都定义在Object类中,因此调用Thread.sleep()是不会影响锁的相关行为。

2、Thread.sleep和Object.wait都会暂停当前的线程,对于CPU资源来说,不管是哪种方式暂停的线程,都表示它暂时不再需要CPU的执行时间。OS会将执行时间分配给其它线程。区别是调用wait后,需要别的线程执行notify/notifyAll才能够重新获得CPU执行时间。

wait和notify

wait():放弃锁,使自己处于等待状态,让其他线程执行。

notify():向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

实现代码如下:

public class Demo {
    static volatile int i = 0;
    static final Object LOCK = new Object();

    public static void add() throws InterruptedException {
        synchronized (LOCK) {
            while (i == 0) {
                System.out.print("add\t");
                System.out.println(++i);
                LOCK.notify();
                LOCK.wait();
            }
        }
    }


    public static void sub() throws InterruptedException {
        synchronized (LOCK) {
            while (i == 1) {
                System.out.print("sub\t");
                System.out.println(--i);
                LOCK.notify();
                LOCK.wait();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

signal()和await()实现

ReentrantLock的signal() / await()是第二种实现方式。利用的是 ReentrantLock 内部的同步对列和条件队列来实现。这个原理需要可以在后面讲解。

public class Demo2 {
    static volatile int i = 0;
    static final ReentrantLock LOCK = new ReentrantLock();
    static final Condition condition = LOCK.newCondition();

    public static void add() throws InterruptedException {
        LOCK.lock();
        try {
            while (i == 0) {
                Thread.sleep(1000);
                System.out.print("add\t");
                System.out.println(++i);
                condition.signal();
                condition.await();
            }
        } finally {
            LOCK.unlock();
        }
    }


    public static void sub() throws InterruptedException {
        LOCK.lock();
        try {
            while (i == 1) {
                Thread.sleep(1000);
                System.out.print("sub\t");
                System.out.println(--i);
                condition.signal();
                condition.await();
            }
        } finally {
            LOCK.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (true) {
                try {
                    add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(() -> {
            while (true) {
                try {
                    sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
相关文章
|
容器
多线程学习之生产者和消费者与阻塞队列的关系
多线程学习之生产者和消费者与阻塞队列的关系
56 0
|
消息中间件 Java 测试技术
Java多线程消费消息
关键词:Java,多线程,消息队列,rocketmq 多线程一个用例之一就是消息的快速消费,比如我们有一个消息队列我们希望以更快的速度消费消息,假如我们用的是rocketmq,我们从中获取消息,然后使用多线程处理。
129 0
|
2月前
|
消息中间件 NoSQL 关系型数据库
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
34 0
|
4月前
|
Java
并发编程之生产者和消费者问题
该博客文章通过Java代码示例介绍了生产者和消费者问题的线程间通信解决方案,演示了如何使用synchronized关键字和wait/notifyAll方法来实现线程间的同步和资源的协调访问。
经典例题:生产者/消费者
经典例题:生产者/消费者
38 0
|
安全 Java
【JUC基础】06. 生产者和消费者问题
学习JUC,就不得不提生产者消费者。生产者消费者模型是一种经典的多线程模型,用于解决生产者和消费者之间的数据交换问题。在生产者消费者模型中,生产者生产数据放入共享的缓冲区中,消费者从缓冲区中取出数据进行消费。在这个过程中,生产者和消费者之间需要保持同步,以避免数据出现错误或重复。今天我们就来说说生产者消费者模型,以及JUC中如何解决该模型的同步问题。
153 0
|
设计模式 安全
生产者与消费者模型
生产者与消费者模型
106 0
生产者与消费者模型
|
存储 算法
生产者与消费者模型:餐厅吃饭问题
生产者与消费者模型:餐厅吃饭问题
120 0
|
消息中间件 RocketMQ
RocketMQ第四章:手把手教老婆实现-顺序消息生产者和顺序消息消费者
RocketMQ第四章:手把手教老婆实现-顺序消息生产者和顺序消息消费者
195 0
RocketMQ第四章:手把手教老婆实现-顺序消息生产者和顺序消息消费者
|
消息中间件 负载均衡 RocketMQ
RocketMQ第七章:手把手教老婆实现-广播消息生产者和消费者
RocketMQ第七章:手把手教老婆实现-广播消息生产者和消费者
176 0
RocketMQ第七章:手把手教老婆实现-广播消息生产者和消费者