LinkedBlockingQueue源码
LinkedBlockingQueue介绍
【1】LinkedBlockingQueue是一个基于链表实现的阻塞队列,默认情况下,该阻塞队列的大小为Integer.MAX_VALUE,由于这个数值特别大,所以 LinkedBlockingQueue 也被称作无界队列,代表它几乎没有界限,队列可以随着元素的添加而动态增长,但是如果没有剩余内存,则队列将抛出OOM错误。所以为了避免队列过大造成机器负载或者内存爆满的情况出现,我们在自定义线程池使用到LinkedBlockingQueue队列时会根据业务需求定义合适的队列容量值capacity。
【2】LinkedBlockingQueue内部由单链表实现,只能从head取元素,从tail添加元素。LinkedBlockingQueue采用两把锁的锁分离技术实现入队出队互不阻塞,分别是写锁putLock和读锁takeLock。添加元素和获取元素都有独立的锁,也就是说LinkedBlockingQueue是读写分离的,读写操作可以并行执行。
LinkedBlockingQueue类的一些关键特性和方法
- 无界队列:如果没有指定容量,队列的容量默认为 Integer.MAX_VALUE。
- 线程安全:通过内部锁机制确保了线程安全。
- FIFO 顺序:元素按照先进先出的方式进行排列。
- 条件对象:使用 ReentrantLock 和 Condition 对象来控制队列的入队和出队操作。
- 动态创建节点:每次插入操作时,除非这会使队列超出其容量,否则都会动态创建新的链表节点。
- 序列化:该类是可序列化的,这意味着它可以被写入到一个输出流中,并从输入流中恢复。
- 迭代器:提供了弱一致性迭代器,用于按顺序访问队列中的元素。
- Spliterator:提供了一个 Spliterator,支持在并行操作中使用 Stream API。
LinkedBlockingQueue使用
//创建有界队列,指定队列的大小为100
BlockingQueue<Runnable> boundedQueue = new LinkedBlockingQueue<>(100);
//无界队列
BlockingQueue<Runnable> unboundedQueue = new LinkedBlockingQueue<>();
LinkedBlockingQueue源码介绍
1.属性值
// 表示队列的容量上限,如果不指定容量值,则为Integer.MAX_VALUE,无限大
private final int capacity;
// 当前队列的元素数量 使用AtomicInteger来实现线程安全的计数器
private final AtomicInteger count = new AtomicInteger();
// 链表的头节点,其item属性总是null,用于标识队列的开始
transient Node<E> head;
// 链表的尾节点,总是指向最后一个节点,其next属性为null
private transient Node<E> last;
// 读锁 控制从队列中取出元素操作
private final ReentrantLock takeLock = new ReentrantLock();
// notEmpty:takeLock的条件对象
// 当拿到takeLock锁并且notEmpty条件对象条件成立也就是队列至少有一条可取数据的时候,才会从队列取出一个元素。
// 拿到takeLock锁,但是队列无元素时,线程会调用notEmpty条件对象的wait方法,这将导致线程释放锁并进入WAITING状态,等待其他线程的唤醒。(注意,offer()方法是非阻塞的,从队列中获取不到数据会返回false)
private final Condition notEmpty = takeLock.newCondition();
// 写锁 控制往队列中添加元素操作
private final ReentrantLock putLock = new ReentrantLock();
// notFull条件
// 当队列满了时,put锁会会阻塞在notFull上,等待其它线程唤醒
// 当拿到putLock锁并且notFull条件对象条件成立也就是队列未满(通过AutomicInteger记录的队列状态来判断当前队列元素数量是否大于队列容量阈值,小于则表示未满),才会往队列中添加元素。
private final Condition notFull = putLock.newCondition();
// 典型的单链表结构
// Node类是一个泛型类,可以存储任何类型的元素(由类型参数E指定)。
static class Node<E> {
E item; // 存储节点中的数据项
Node<E> next; // 单链表结构 指向链表中的下一个节点,有三种可能的值:
// 1.真实的后继节点。
// 2.this Node,这通常意味着后继是head.next,这可能是在初始化时或者在某些特殊情况下使用。
// 3.null,表示没有后继节点,即当前节点是链表的最后一个节点。
Node(E x) { item = x; } // 有参构造函数
}
2.构造器
public LinkedBlockingQueue() {
// 如果没传容量,就使用最大int值初始化其容量
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
// 初始化head和last指针为空值节点
last = head = new Node<E>(null);
}
// TaskQueue队列才会使用到这个有参够咱
// 这是构造器的声明,它接受一个Collection类型的参数c,该参数中的元素类型是E的子类型。
public LinkedBlockingQueue(Collection<? extends E> c) {
// 调用LinkedBlockingQueue的另一个有参构造器,将队列的容量设置为Integer.MAX_VALUE&#