一、ArrayBlockingQueue中putIndex和takeIndex为什么不用volatile修饰

因为take和put操作共用一把锁:ReentrantLock,已经解决了可见性问题

二、ArrayBlockingQueue为什么对数组操作要设计成双指针?

保持常规操作O(1)时间复杂度。
常规数组操作,如果保证先进先出,出队后,整个数组元素需要前移。导致额外的性能开销。而唤醒数组则可以不用前移。
image.png

三、LinkedBlockingQueue与ArrayBlockingQueue对比

LinkedBlockingQueue是一个阻塞队列,内部由两个ReentrantLock来实现出入队列的线程安全,由各自的Condition对象的await和signal来实现等待和唤醒功能。
和ArrayBlockingQueue的不同点在于:

  • 队列大小有所不同,ArrayBlockingQueue是有界的初始化必须指定大小,而LinkedBlockingQueue可以是有界的也可以是无界的(Integer.MAX_VALUE),当设置为无界时,当添加速度大于移除速度时,在无界的情况下,可能会造成内存溢出等问题。
  • 数据存储容器不同,ArrayBlockingQueue采用的是数组作为数据存储容器,而LinkedBlockingQueue采用的则是以Node节点作为连接对象的链表。
  • 由于ArrayBlockingQueue采用的是数组的存储容器,因此在插入或删除元素时不会产生或销毁任何额外的对象实例,而LinkedBlockingQueue则会生成一个额外的Node对象。在长时间内需要高效并发地处理大批量数据的时,对于GC可能存在较大影响
  • 两者的实现队列添加或移除的锁不一样,ArrayBlockingQueue实现的队列中的锁是没有分离的,即添加操作和移除操作采用的同一个ReenterLock锁,而LinkedBlockingQueue实现的队列中的锁是分离的,添加采用的是putLock,移除采用的则是takeLock,大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。

四、阻塞队列选择

1.功能:是否可直接使用的功能。(优先级、延迟等功能)
2.容量:SynchronousQueue没有容量;ArrayBlockingQueue固定容量;LinkedBlockingQueue无线容量;PriorityBlockingQueue 初始化容量,但可以无线扩容
3.底层存储结构:ArrayBlockingQueue数组;LinkedBlockingQueue链表
4.并发性:ArrayBlockingQueue入队出队一把锁。LinkedBlockingQueue 锁分离,性能较高