双非本科准备秋招(20.1)—— 并发编程之生产者消费者

本文详细介绍了Java中的生产者消费者模型,通过MessageQueue类的实例,展示了生产者负责生成消息并放入队列,消费者负责从队列取出并处理消息的过程,同时利用synchronized、wait和notify实现线程间的协作。
摘要由CSDN通过智能技术生成

生产者消费者

与保护性暂停中的不同,不需要产生结果和消费结果的线程一一对应

生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据

JDK 中各种阻塞队列,采用的就是这种模式

代码实现:

        首先,设计消息队列类MessageQueue,需要指定容量capacity,用双向链表list作为容器。

        提供take方法:检查list是否是空,空的话就wait,如果不空就打印Message,并唤醒所有线程。

        提供put方法:检查list是否满了,满了的话就wait,如果不满就添加Message,并唤醒所有线程。

        可以看到,以上的写法都是使用wait和notify的模板写法。

class MessageQueue{
    private LinkedList<Message> list = new LinkedList<>();
    private int capacity;
    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    //取
    public Message take(){
        synchronized (list){
            while (list.isEmpty()){
                try {
                    log.debug("队列空了");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Message message = list.removeFirst();
            log.debug("取出来了{}", message);
            list.notifyAll();
            return message;
        }
    }

    //存
    public void put(Message message){
        synchronized (list){
            while(list.size() == capacity){
                try {
                    log.debug("队列满了");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.addLast(message);
            log.debug("添加了{}", message);
            list.notifyAll();
        }
    }
}

        设计Message类,需要一个唯一标识id,还需要一个Object类型的value值。

final class Message{
    private int id;
    private Object value;

    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}

         完整代码:

public class ProductAndConsumer {
    public static void main(String[] args) {
        MessageQueue q = new MessageQueue(3);
        for (int i = 1; i <= 5; i++){
            //lambda表达式必须传final的值,不能变。
            int id = i;
            new Thread(()->{
                q.put(new Message(id, "v"+id));
            }, "生产者").start();
        }

        new Thread(()->{
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message t = q.take();
            }
        }, "消费者").start();
    }
}

/**
 * 消息队列类
 */
@Slf4j(topic = "c.test")
class MessageQueue{
    private LinkedList<Message> list = new LinkedList<>();
    private int capacity;
    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    //取
    public Message take(){
        synchronized (list){
            while (list.isEmpty()){
                try {
                    log.debug("队列空了");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Message message = list.removeFirst();
            log.debug("取出来了{}", message);
            list.notifyAll();
            return message;
        }
    }

    //存
    public void put(Message message){
        synchronized (list){
            while(list.size() == capacity){
                try {
                    log.debug("队列满了");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.addLast(message);
            log.debug("添加了{}", message);
            list.notifyAll();
        }
    }
}


/**
 * Message对象,只有get方法,并且final不可继承,也不会被子类重写方法,很安全。
 */
final class Message{
    private int id;
    private Object value;

    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}

 某次的运行结果

21:17:06 [生产者] c.test - 添加了Message{id=5, value=v5}
21:17:06 [生产者] c.test - 添加了Message{id=2, value=v2}
21:17:06 [生产者] c.test - 添加了Message{id=3, value=v3}
21:17:06 [生产者] c.test - 队列满了
21:17:06 [生产者] c.test - 队列满了
21:17:07 [消费者] c.test - 取出来了Message{id=5, value=v5}
21:17:07 [生产者] c.test - 添加了Message{id=1, value=v1}
21:17:07 [生产者] c.test - 队列满了
21:17:08 [消费者] c.test - 取出来了Message{id=2, value=v2}
21:17:08 [生产者] c.test - 添加了Message{id=4, value=v4}
21:17:09 [消费者] c.test - 取出来了Message{id=3, value=v3}
21:17:10 [消费者] c.test - 取出来了Message{id=1, value=v1}
21:17:11 [消费者] c.test - 取出来了Message{id=4, value=v4}
21:17:12 [消费者] c.test - 队列空了
  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值