资料内容:
队列是一种 FIFO(先进先出)的数据结构,JDK 中定义了 java.util.Queue 的队列接口,与 List、Set 接 口类似,java.util.Queue 也继承于 Collection 集合接口。 此外,JDK 还提供了一种双端队列接口 java.util.Deque,我们最常用的 LinkedList 就是实现了 Deque
接口。 下面我们简单说说上图中的每个队列的特点,并给出一些对比和总结。
阻塞队列
阻塞队列在队列为空或者队列满时,都会发生阻塞。阻塞队列自身是线程安全的,使用者无需关心线程 安全问题,降低了多线程开发难度。 阻塞队列主要分为以下几种:
ArrayBlockingQueue: 最基础且开发中最常用的阻塞队列,底层采用数组实现的有界队列,初始化需要指定队列的容量。
ArrayBlockingQueue 是如何保证线程安全的呢? 它内部是使用了一个重入锁 ReentrantLock,并搭配 notEmpty、notFull 两个条件变量 Condition 来控制并发访问。 从队列读取数据时,如果队列为空,那么会阻塞等待,直到队列有数据了才会被唤醒。 如果队列已经满了,也同样会进入阻塞状态,直到队列有空闲才会被唤醒。
LinkedBlockingQueue: 内部采用的数据结构是链表,队列的长度可以是有界或者无界的,初始化不需要指定队列长度,默 认是 Integer.MAX_VALUE。
LinkedBlockingQueue 内部使用了 takeLock、putLock两个重入锁 ReentrantLock,以及 notEmpty、notFull 两个条件变量 Condition 来控制并发访问。 采用读锁和写锁的好处是可以避免读写时相互竞争锁的现象,所以相比于 ArrayBlockingQueue,
LinkedBlockingQueue 的性能要更好。