前言
日常开发中,咱们最罕用的汇合次要有两个,一个是ArrayList,一个是LinkedList
如果对ArrayList还有不明确的同学,能够看一下我之前写的一篇文章:Java汇合,ArrayList源码深刻解析
那么本篇文章,咱们次要是基于LinkedList写一个简略的队列。
设计思路:
首先咱们想要设计一个计划的时候,要先捋分明思路,想一下现有的,他人曾经实现的计划,而后思考本人如何能力实现。(比方rabbitMq)
队列管理中心:集中管理所有创立的队列
提供方:往音讯队列中发送音讯
生产方:监听音讯队列中的音讯,并进行生产(如果监听到队列中新放入了音讯,则主动生产解决)
第一步:实现音讯队列
咱们要明确队列所须要实现的性能,次要是发送音讯,接管音讯。
package com.dm.black.modules.myQuere;import java.util.LinkedList;/** * 基于LinkedList实现音讯队列 * @author wjy * @date 2021/1/20 */public class MQueue extends QueueCenter { private LinkedList<Object> queue = new LinkedList<>(); /** * 留神:这里加锁是为了避免并发操作,因为LinkedList自身是线程不平安的 * @method 放入音讯 * @param o * @return */ public boolean putMessage(Object o) { synchronized (queue) { // 如果队列在期待,则执行唤醒 if (queue.isEmpty()) { System.out.println("唤醒队列..."); queue.notifyAll(); } // 将音讯放入队列 queue.push(o); return true; } } /** * @method 取得音讯(获取首条音讯并删除) * @return */ public Object pollFirst() { synchronized (queue) { // 如果队列中没有音讯,则处于梗塞状态,有音讯则进行生产 if (queue.isEmpty()) { try { System.out.println("队列中没有数据,开始期待...."); queue.wait(); // 被唤醒后,持续往下执行 Object o = queue.pollFirst(); return o; } catch (InterruptedException e) { e.printStackTrace(); } } else { Object o = queue.pollFirst(); return o; } } return null; } /** * 取得音讯(获取首条音讯但不删除) * @return */ public Object getFrist(){ synchronized (queue) { Object first = queue.getFirst(); return first; } } /** * 队列中是否存在音讯 * @return */ public boolean isReady() { if (!queue.isEmpty()) { return true; } return false; }}
第二步:实现音讯队列管理中心
目标:为了将队列统一化治理,比方N个注册者,或者 N个消费者应用雷同名称的队列时,保障操作的是同一个队列。
package com.dm.black.modules.myQuere;import java.util.HashMap;import java.util.Map;/** * Queue-center * @author wjy * @date 2021/1/20 */public class QueueCenter { /** * @description 这里应用Map 作为队列管理中心 * 创立一个queue管理中心,所有创立的Queue在这里进行治理 * Map -> key : queue名称 * Map -> value : 队列 */ private static Map<String, MQueue> queueCenter = new HashMap<>(); /** * @method 从 Queue-center 获取 Queue * 加锁目标:避免同时创立雷同名称的queue */ public static MQueue getQueue(String queueName) { synchronized (queueName) { // 从map中依据名称获取队列,如果曾经存在,则返回map中的队列 MQueue queue = queueCenter.get(queueName); // 如果是第一次创立队列,则新建队列并放入map,而后将新建的队列返回 if (queue == null) { queue = new MQueue(); putQueue(queueName, queue); MQueue mQueue = queueCenter.get(queueName); return mQueue; } return queue; } } /** * @method 将 Queue 放入 Queue-center * @param queueName */ private static void putQueue(String queueName, MQueue queue) { queueCenter.put(queueName, queue); }}
第三步:音讯注册
咱们要实现一个提供方,将音讯放入队列中,供生产方应用
package com.dm.black.modules.myQuere;/** * 注册者 * @author wjy * @date 2021/1/20 */public class MProvider { // 队列名称 private final String queueName = "demo"; /** * 发送音讯到'demo'队列 * @param message */ public void sendMessage(String message) { // 获取到queue MQueue queue = QueueCenter.getQueue(queueName); // 放入音讯 queue.putMessage(message); System.out.println("提供者:" + queueName + ": 发送音讯:" + message); }}
第四步:音讯者实现
其实到这里,音讯注册和音讯生产曾经实现了,然而咱们想要做到的是一个能够主动生产音讯的队列,所以思路是,咱们要在我的项目启动时,就将消费者处于就绪状态,提供者发送音讯后,消费者能够实时进行生产。
package com.dm.black.modules.myQuere;import java.util.LinkedList;/** * 消费者 * @author wjy * @date 2021/1/20 */public class MConsumer { private final String queueName = "demo"; /** * 接管音讯并删除 */ public void receiveMessageAndDelete() { MQueue queue = QueueCenter.getQueue(queueName); // 如果队列中存在音讯,则始终处于生产状态 while (true) { // 生产音讯, 执行巴拉巴拉一大堆业务解决后删除 Object o = queue.pollFirst(); System.out.println("消费者:" + queueName + ": 接管到音讯:" + o.toString()); } }}
如何让消费者就处于随时生产音讯的状态呢?答案就是在我的项目启动式,就初始化消费者,让消费者实时的去监听音讯。
package com.dm.black;import com.dm.black.modules.myQuere.MConsumer;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.dm.black.modules.*.mapper")@SpringBootApplicationpublic class BlackApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(BlackApplication.class, args); } @Override public void run(String... strings) throws Exception { // 启动消费者 MConsumer mConsumer = new MConsumer(); mConsumer.receiveMessageAndDelete(); }}
测试
咱们提供一个controller来注册音讯
package com.dm.black.modules.myQuere;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @author wjy * @date 2021/1/22 */@RestController@RequestMapping("/mQueue")public class MQueueController { @GetMapping("/sendMessage") public String sendMessage(String message) { MProvider mProvider = new MProvider(); mProvider.sendMessage(message); return "success"; }}
咱们看到,当我的项目启动的时候,消费者曾经处于就绪状态,队列中没有音讯,所以处于梗塞状态,当监听到音讯后,立马工作进行生产。
咱们调用一下
看一下控制台输入
能够看到,提供者第一次注册音讯时,将队列唤醒,并注册到队列中,消费者监听到音讯,立马开始工作。
到这里咱们曾经实现了一个简易版的音讯队列,如果对大家有帮忙,心愿多多反对。
因为没有新起我的项目去做这个Demo,所以就不提供源码了,大家自行copy我贴出来的代码吧