第10篇 rabbitmq LinkedBlockingQueue(上篇)

10 篇文章 0 订阅

这节主要分析和学习LinkedBlockingQueue队列特性,具体类图如下,我们理解它如何实现阻塞, 主要研究LinkedBlockingQueue的父类依赖抽象类和接口解析

image-20210609100149196

1、分析上图

  • 队列是集合的一种
  • BlockingQueue接口却不继承AbstractQueue 也说明它不同于一般的队列,也就在普通队列增加新特性一样(类似马添加翅膀的属性,它就具有飞功能)
  • 它还实现Serializable接口说明具有在中网络传递该对象功能,支持序列化和反序列化
  • Iterable接口 需要实现 迭代器功能

2、Iterable 接口

  • 实现这个接口是为了可以使用 for-each 循环代码 (jdk1.5 就存在了)
  • T代表迭代元素类型
  • 细心可以发现对于接口具有什么能力一般形容词的,就前面学习Closable接口也是,实现这个Closable接口就有关闭资源的能力。

2.1、接口方法 (核心方法Iterator)

  • Iterator iterator() 返回一个迭代器 ( jdk1.5 存在)
  • void forEach (Consumer<? super T> action) for-each循环函数版功能,action就是要自己定义遍历需要做什么逻辑操作,且只接受一个参数,接收两个参数就用BiConsumer,是不是很好理解 (jdk1.8)
  • Spliterator spliterator() 分离器(把集合分割小份处理) (jdk1.8)

2.1.2、Iterator 接口

  • Iterator就是迭代集合工具,也是替代Enumration(枚举类),迭代器与枚举不同地方
    1. 迭代器允许调用者在具有明确定义语义的迭代期间从底层集合中删除元素。
    2. 方法名更简洁
2.1.2.3、Iterator 接口方法
  • boolean hasNext() 是否下一个元素, true表示有
  • E next() 返回下一个元素
  • void remove() 移除元素, 必须先调用next() 在调用remove方法,且只能调用一次
  • void forEachRemaining(Consumer<? super E> action) 为剩下元素做迭代具体功能逻辑

3、Collection 接口

  • 所有集合父类,集合含义就是一组元素的指代,元素和元素之间的关系就增加集合一些新的属性,比如元素能不能重复? 元素顺序如何?(那个元素排在前面),要不要保证有序呢? 这样有分支去区分这些属性,这样就有Set(不能重复), List 保证有序
  • 对应Collection需要提供一个无参构造方法和有Collection参数的构造方法,不能集合之间可以进行转换,从集合A把元素放到集合B
  • 自定集合时候可以提供能力,不能支持能力我们应该抛出UnsupportedOperationException异常,比如我们不支持在迭代是修改元素(移除和添加)
  • 有些特殊元素集合是否支持,比如说null元素
  • 在实现集合时候需要考虑线程安全问题
  • 考虑到两个元素是否相等,需要重写hashCode 和equals, 其实你会发现hashCode 存粹是为集合考虑的方法

3.1、Collection接口方法

  • int size 集合是有多少元素 最大只能Integer.MAX_VALUE, 超过就返回Integer.MAX_VALUE

  • boolean isEmpty() 集合是否为空

  • boolean contains(Object o) 包含某个元素(如果集合允许null,就不能直接使用equals方法)

  • Iterator iterator() 返回迭代器 ( Iterable接口中方法)

  • Object[] toArray() 集合变成数组 ,线程安全新开一个数组存集合元素,而不是用原来集合的数组,还一个点是否需要保证顺序

  • T[] toArray(T[] a) 将集合转换成特定类型数组 (如果定义数组长度大于集合长度,对应没有值设置为null,一般我们会用0 例如,将x转换成字符串数组),是否需要保序

    • String[] y = x.toArray(new String[0]);
      
  • boolean add (E e) 添加元素 添加成功返回true,(元素是否重复,元素是否可以为null,元素添加时机对不对,添加元素类型对不对,可以有很多限制)

  • boolean remove(Object o) 移除元素(如果集合允许重复,两个A元素,是否调用一次remove(A)方法将两个A元素全部移除?),如果你细心的话你会发现,remove和contains都是确定Object对象,而不是泛型E,这两个方法只需知道equals和hashCode结果即可,而这个两个方法就是在Object就有

  • boolean containsAll(Collection<?> c) c集合是否为该集合的子集

  • boolean addAll(Collection<? extends E> c) 添加集合中元素,将一个集合元素转换成另一个集合元素

  • boolean removeAll (Collection<?> c); 移除集合c在该集合的元素

  • boolean removeIf(Predicate<? super E> filter) 移除符合条件元素(更加灵活了),顺便学习一下Predicate函数

  • boolean retainAll(Collection<?> c) 该集合与c集合的交集

  • void clear() 清空集合

  • boolean equals(Object o); list和set需要不同实现

  • int hashCode() 如果两个元素相等,我们要确定hashCode也是相等的

  • Spliterator spliterator() 分离器

  • Stream stream() jdk 1.8 流

  • Stream parallelStream 并行流

3.2、小结

  • 集合最重要是 equals(Object o) 和hashCode()重写 ,这个两个方法决定元素之间的关系
  • 集合本质:物以类聚

4、AbstractCollection 抽象类

  • 对集合一般方法的实现,所有集合的骨架,集合通用方法能实现就尽量实现
  • 对于不可变集合的实现,只需要继承和实现iterator()和size()方法,其他iterator中hasNext()和next()方法也需要实现
  • 对于可变集合的实现,必须额外重写add方法和iterator中remove方法
  • 一般我需要提供一个无参构造函数和有一个Collection参数的构造函数

4.1、实现方法

  • java.util.AbstractCollection#isEmpty size==0
  • java.util.AbstractCollection#contains null和非null是否包含
  • java.util.AbstractCollection#toArray() 集合转数组
    • image-20210609145546332
  • java.util.AbstractCollection#add 添加元素默认是不支持的
  • java.util.AbstractCollection#remove 移除元素 也分为null和非null
  • java.util.AbstractCollection#containsAll 是否全部包含
  • java.util.AbstractCollection#addAll 只有添加一个元素进去就返回true
  • java.util.AbstractCollection#removeAll 只有移除一个元素成功就返回true
  • java.util.AbstractCollection#retainAll 取交集
  • java.util.AbstractCollection#clear 移除所有元素
  • java.util.AbstractCollection#toString 重写toString()方法 ,没有元素返回"[]"

5、Queue接口 extends Collection

  • FIFO (first-in-first-out) 先进先出
  • 添加、移除、弹出头部元素都有两个方法,一个抛出异常,一个是返回null值

5.1、Queue方法

方法名含义
boolean add(E e)添加元素,如果满会抛出IllegalStateException异常
boolean offer(E e)添加元素,没有返回null
E remove()移除元素 如果元素不存在抛出NoSuchElementException
E poll()移除元素,没有返回null
E element查看header元素,如果不存抛出NoSuchElementException
E peek()查看header元素,没有返回null
  • 总结
    • add 、remove、element可能会抛出异常
    • offer、poll、peek 不会抛出 IllegalStateException和NoSuchElementException

6、AbstractQueue 抽象类

  • 这个类提供queue一般骨架

6.1、AbstractQueue方法

  • 提供一个无参构造方法
  • 实现方法
boolean add(E e)调用offer(e)方法,如果新增失败返回IllegalStateException(“Queue full”)
E remove调用poll()方法,如果不存在,返回NoSuchElementException异常
E element获取头部元素,如果不存在,返回NoSuchElementException异常
void clear()清除所有元素
boolean addAll(Collection<? extends E> c)将集合c元素添加到当前队列中,使用add(E e)

7、BlockingQueue 接口 extends Queue

操作/结果抛出异常返回特定值阻塞超时
插入/新增add(e)offer(e)put(e)offer(e,time,unit)
移除remove()poll()take()poll(long, unit)
查看头部元素element()peek()----------
  • BlockingQueue是不支持null元素的

  • BlockingQueue可能有容量限制,默认Integer.MAX_VALUE

  • BlockingQueue典型用于生产者和消费者模型中,但是它支持Collection操作,只是在特殊取消某个对象消息使用(如下示例)

    • /**
       * @author liangchen
       * @date 2021/6/9
       */
      public class BlockingQueueTest {
          public static void main(String[] args) {
              BlockingQueue q = new ArrayBlockingQueue(10);
              Producer p = new Producer(q);
              Consumer c1 = new Consumer(q);
              Consumer c2 = new Consumer(q);
              new Thread(p).start();
              new Thread(c1).start();
              new Thread(c2).start();
          }
      }
      
      class Producer implements Runnable {
          private final BlockingQueue queue;
      
          Producer(BlockingQueue q) {
              queue = q;
          }
      
          public void run() {
              try {
                  while (true) {
                      queue.put(produce());
                  }
              } catch (InterruptedException ex) {
                  ex.printStackTrace();
              }
          }
      
          Object produce() {
      
              Object o = new Object();
              System.out.println("produce ====" + o);
              return o;
          }
      }
      
      class Consumer implements Runnable {
          private final BlockingQueue queue;
      
          Consumer(BlockingQueue q) {
              queue = q;
          }
          public void run() {
              try {
                  while (true) {
                      consume(queue.take());
                  }
              } catch (InterruptedException ex) {
                  ex.printStackTrace();
              }
          }
          void consume(Object x) {
              System.out.println("consume===" + x);
          }
      }
      
      
      
  • BlockingQueue实现必须线程安全的,但是对于批量操作没有必要保持原子性,也就说有可能添加部分元素或移除部分元素(例如addAll,removeAll)

  • 如何确定BlockingQueue已经满了,一般需要实现者在末尾添加特殊表示结束的对象

  • BlockingQueue内存一致性影响,两个线程同时操作同一个队列情况

6.1、BlockingQueue接口方法

方法名含义
boolean add(E e)添加元素,如果满会抛出IllegalStateException异常
boolean offer(E e)添加元素,没有返回null
void put( E e) throws InterruptedException添加元素,一直等待可以插入数据
E remove()移除元素 如果元素不存在抛出NoSuchElementException
E poll()移除元素,没有返回null
E take() throws InterruptedException等待可移除元素
int remainingCapacity()预计剩余可以添加元素个数
boolean contains(Obejct o)包含特定元素
int drainTo(Collection<? super E> c)将队列元素添加到集合c中
int drainTo(Collection<? super E> c, int maxElements)将队列元素添加集合c中(最多元素个数是maxElements

6.2、blockingQueue总结

  • 核心方法put和take 阻塞添加和拿取
  • drainTo 将队列元素添加到集合c中

7、Serializable

  • 需要实现序列化和反序列方法 writeObject 和readObject()

总结

  • 本节主要熟悉LinkedBlockingQueue父级接口和抽象类的情况
  • 由于LinkedBlockingQueue本类还算比较复杂,东西还是有点,暂时先写到这里,下一节将写LinkedBlockingQueue本身

结尾

  • 感谢大家的耐心阅读,如有建议请私信或评论留言。
  • 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步
  • 下一篇研究一下 LinkedBlockingQueue 本身
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SimpleMessageListenerContainer 是 RabbitMQ 客户端提供的一个用于消息监听的容器,它可以实现对消息的自动监听、自动连接和重连等功能。SimpleMessageListenerContainer 的使用对于 RabbitMQ 的消息监听非常方便。 下面我们来看一下 SimpleMessageListenerContainer 的使用方法: 首先,我们需要添加 RabbitMQ 的依赖: ```xml <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> <version>2.2.11.RELEASE</version> </dependency> ``` 然后,我们需要在 Spring 配置文件中配置相关的 Bean: ```xml <!-- 创建一个 ConnectionFactory --> <bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory"> <property name="addresses" value="localhost:5672" /> <property name="username" value="guest" /> <property name="password" value="guest" /> <property name="virtualHost" value="/" /> </bean> <!-- 配置 RabbitAdmin --> <bean id="rabbitAdmin" class="org.springframework.amqp.rabbit.core.RabbitAdmin"> <constructor-arg ref="connectionFactory" /> </bean> <!-- 配置 SimpleMessageListenerContainer --> <bean id="simpleMessageListenerContainer" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="queueNames" value="test.queue" /> <property name="messageListener" ref="messageListener" /> </bean> <!-- 配置 MessageListener --> <bean id="messageListener" class="com.example.MessageListener" /> ``` 其中,ConnectionFactory 为连接 RabbitMQ 的工厂类,RabbitAdmin 为 RabbitMQ 的管理器,SimpleMessageListenerContainer 为消息监听容器,queueNames 表示需要监听的队列名称,messageListener 表示消息的监听器类。 最后,我们需要编写一个消息监听器类 MessageListener: ```java public class MessageListener implements ChannelAwareMessageListener { @Override public void onMessage(Message message, Channel channel) throws Exception { System.out.println("接收到消息:" + new String(message.getBody())); channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } } ``` 在这个类中,我们实现了 ChannelAwareMessageListener 接口,它是 Spring AMQP 提供的一个用于消息监听的接口,其中 onMessage 方法为消息监听回调方法。 至此,我们就可以使用 SimpleMessageListenerContainer 来实现 RabbitMQ 的消息监听了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值