• 多线程之模拟自定义消息队列


    1.背景

    面试官问,假设让你设计一个队列,你的思路是...

    2.代码

    package com.ldp.demo01;
    
    import com.common.MyThreadUtil;
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.LinkedList;
    
    /**
     * @author 姿势帝-博客园
     * @address https://www.cnblogs.com/newAndHui/
     * @WeChat 851298348
     * @create 01/31 8:24
     * @description
     */
    @Slf4j
    public class Test08MessageQueue {
        /**
         * 测试自定义的队列
         *
         * @param args
         */
        public static void main(String[] args) {
            // 创建队列
            MessageQueue queue = new MessageQueue(2);
            // 模拟4个生产者参数数据到队列
            for (int i = 0; i < 4; i++) {
                int n = i + 1;
                new Thread(() -> {
                    int m = 1;
                    // 不停的循环放入数据
                    while (true) {
                        int k = n * 1000 + m;
                        Message message = new Message(k, "消息-" + k);
                        log.info("放入的消息是:{}", message);
                        queue.put(message);
                        m++;
                    }
                }, "生产者-" + n).start();
            }
            // 模拟2个消费者到队列中取数据
            for (int i = 0; i < 1; i++) {
                int n = i + 1;
                new Thread(() -> {
                    // 每个消费者都是不停的取数据
                    while (true) {
                        // 每隔2秒取一次
                        MyThreadUtil.sleep(2);
                        Message message = queue.take();
                        log.info("取到的消息是:{}", message);
                    }
                }, "消费者-" + n).start();
            }
        }
    }
    
    @Slf4j
    class MessageQueue {
        /**
         * 队列的容量
         */
        private Integer capacity;
        /**
         * 装消息的队列
         */
        private LinkedList<Message> list = new LinkedList<>();
    
        public MessageQueue(Integer capacity) {
            this.capacity = capacity;
        }
    
        /**
         * 获取一条消息
         *
         * @return
         */
        public Message take() {
            synchronized (list) {
                while (list.isEmpty()) {
                    try {
                        // log.debug("无数据,等待中....");
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 取出头部消息,并删除
                Message message = list.removeFirst();
                // 通知放入队列
                list.notifyAll();
                return message;
            }
        }
    
        /**
         * 放入一条数据
         *
         * @param message
         */
        public void put(Message message) {
            synchronized (list) {
                while (list.size() >= capacity) {
                    try {
                        //  log.debug("队列已满,当前队列数:{},最大队列数:{}", list.size(), capacity);
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 放入队列
                list.addLast(message);
                // 通知消费者取数据
                list.notifyAll();
            }
        }
    }
    
    /**
     * 消息对象
     * 使用final不让其被继承,避免修改消息
     */
    final class Message {
        private Integer id;
        private Object object;
    
        /**
         * 提供一个构造方法
         *
         * @param id
         * @param object
         */
        public Message(Integer id, Object object) {
            /**
             * 消息id
             */
            this.id = id;
            /**
             * 具体的消息内容
             */
            this.object = object;
        }
    
        /**
         * 只提供获取方法,让消息不可以修改
         *
         * @return
         */
        public Integer getId() {
            return id;
        }
    
        public Object getObject() {
            return object;
        }
    
        @Override
        public String toString() {
            return "Message{" +
                    "id=" + id +
                    ", object=" + object +
                    '}';
        }
    }

    完美

  • 相关阅读:
    程序中不要出现标识符完全相同的局部变量和全局变量
    不要出现仅靠大小写区分的相似的标识符
    程序中不要出现仅靠大小写区分的相似的标识符
    命名规则尽量与所采用的操作系统或开发工具的风格保持一致
    标识符的长度应当符合“min-length && max-information”原则
    标识符应当直观且可以拼读,可望文知意,不必进行“解码”
    当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释
    注释的位置应与被描述的代码相邻
    尽量避免在注释中使用缩写
    注释应当准确、易懂,防止注释有二义性
  • 原文地址:https://www.cnblogs.com/newAndHui/p/15858012.html
Copyright © 2020-2023  润新知