java消息队列理解

java筑基 · 2019-06-14 · 221 人浏览

今天看到我们的招聘信息有对消息队列有要求,然后就思索了一翻,网上一搜一大堆。


消息队列,顾名思义 首先是个队列。
队列的操作有

入队
出队

也就是你有一个程序在产生内容然后入队(生产者) 另一个程序读取内容,内容出队(消费者)

这是最最基本的概念。

我想你应该是缺乏一个使用场景。

当你不需要立即获得结果,但是并发量又不能无限大的时候,差不多就是你需要使用消息队列的时候。

比如你写日志,因为可能一个客户端有多个操作去写,又有很多个客户端,显然并发不能无穷大,于是你就需要把写日志的请求放入到消息队列里,在消费者那边依次把队列中产生的日志写到数据库里。

至于怎么实现消息队列,其实你本身一个普通的队列就行呀~看你需要什么附加功能而已。


我可以举个小例子先说明应用场景

假设你的服务器每分钟的处理量为200个,但客户端再峰值的时候可能一分钟会发1000个消息给你,这时候你就可以把他做成队列,然后按正常有序的处理,先进后出(LIFO),先进先出(FIFO)可根据自己的情况进行定夺

stack  先进后出(LIFO)--------Java 对应的类 Stack

队列 先进先出(FIFO)--------java对应的类Queue

这两种都可用Linkedlist进行封装和实现,下面是我自己写的一个栈的例子


[java] view plain copy 在CODE上查看代码片派生到我的代码片

  1. /** 

  2.  * @author 刘伊凡 

  3.  * --------->>>>>>队列的实现-------------- 

  4.  */  

  5. public class MyStack<T> {  

  6.     private LinkedList<T> storage = new LinkedList<T>();  

  7.   

  8.     public synchronized void push(T e) {//需要加上同步  

  9.         storage.addFirst(e);  

  10.     }  

  11.   

  12.     public T peek() {  

  13.         return storage.getFirst();  

  14.     }  

  15.   

  16.     public void pop() {  

  17.         storage.removeFirst();  

  18.     }  

  19.   

  20.     public boolean empty() {  

  21.         return storage.isEmpty();  

  22.     }  

  23.   

  24.     @Override  

  25.     public String toString() {  

  26.         return storage.toString();  

  27.     }  

  28.   

  29. }  


下面是一个测试类



[java] view plain copy 在CODE上查看代码片派生到我的代码片

  1. /** 

  2.  * @author 刘伊凡 

  3.  * 

  4.  */  

  5. public class StackTest {  

  6.     public static void main(String[] args) {  

  7.         MyStack<String> stack = new MyStack<String>();  

  8.         for(String s : "the prefect code".split(" ")){//LIFO  

  9.             stack.push(s);  

  10.         }  

  11.         while(!stack.empty()){  

  12.             System.out.print(stack.peek()+" ");  

  13.             stack.pop();  

  14.         }  

  15.           

  16.         System.out.println();  

  17.         for(char s : "写了个一句话倒起来说的程序".toCharArray()){//用例:正话反说  

  18.             stack.push(String.valueOf(s));  

  19.         }  

  20.         while(!stack.empty()){  

  21.             System.out.print(stack.peek());  

  22.             stack.pop();  

  23.         }  

  24.     }  

  25. }  


挺有意思的,让我想了,以前在学校的晚会上,主持人互动的时候会让人上台去答题拿奖品,其中有一个题目就是主持人说一句话,然后要求选手倒起来说,我们的这个程序很符合需求嘛,哈哈,我们可以用java来作弊,学以致用


消息队列的应用场景,补充(来自互联网)


个人认为消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。

使用场景的话,举个例子:
假设用户在你的软件中注册,服务端收到用户的注册请求后,它会做这些操作:

  1. 校验用户名等信息,如果没问题会在数据库中添加一个用户记录

  2. 如果是用邮箱注册会给你发送一封注册成功的邮件,手机注册则会发送一条短信

  3. 分析用户的个人信息,以便将来向他推荐一些志同道合的人,或向那些人推荐他

  4. 发送给用户一个包含操作指南的系统通知

  5. 等等……

但是对于用户来说,注册功能实际只需要第一步,只要服务端将他的账户信息存到数据库中他便可以登录上去做他想做的事情了。至于其他的事情,非要在这一次请求中全部完成么?值得用户浪费时间等你处理这些对他来说无关紧要的事情么?所以实际当第一步做完后,服务端就可以把其他的操作放入对应的消息队列中然后马上返回用户结果,由消息队列异步的进行这些操作。

或者还有一种情况,同时有大量用户注册你的软件,再高并发情况下注册请求开始出现一些问题,例如邮件接口承受不住,或是分析信息时的大量计算使cpu满载,这将会出现虽然用户数据记录很快的添加到数据库中了,但是却卡在发邮件或分析信息时的情况,导致请求的响应时间大幅增长,甚至出现超时,这就有点不划算了。面对这种情况一般也是将这些操作放入消息队列(生产者消费者模型),消息队列慢慢的进行处理,同时可以很快的完成注册请求,不会影响用户使用其他功能。

所以在软件的正常功能开发中,并不需要去刻意的寻找消息队列的使用场景,而是当出现性能瓶颈时,去查看业务逻辑是否存在可以异步处理的耗时操作,如果存在的话便可以引入消息队列来解决。否则盲目的使用消息队列可能会增加维护和开发的成本却无法得到可观的性能提升,那就得不偿失了。