ArrayBlockingQueue的put方法底层原理

一、ArrayBlockingQueue的put方法底层原理

ArrayBlockingQueue 是 Java 并发包 (java.util.concurrent) 中的一个基于数组实现的有界阻塞队列。它的 put 方法是用于向队列中插入元素的核心方法之一。当队列满时,put 方法会阻塞当前线程,直到队列有空闲空间


1、put 方法的功能

  • 作用:将元素插入到队列的尾部

  • 阻塞行为:如果队列已满,当前线程会被阻塞,直到队列有空闲空间

  • 线程安全:put 方法是线程安全的,内部通过锁机制实现同步


2、put 方法的源码分析

以下是 ArrayBlockingQueue 中 put 方法的源码(基于 JDK 17):


关键点解析

  • 1、获取锁:

    • 使用 lock.lockInterruptibly() 获取锁,支持线程中断

    • 如果当前线程被中断,会抛出 InterruptedException

  • 2、检查队列是否满:

    • 如果队列满(count == items.length),调用 notFull.await() 使当前线程等待

    • notFull 是一个 Condition 对象,用于表示队列未满的条件

  • 3、插入元素:

    • 如果队列未满,调用 enqueue(e) 方法将元素插入队列

    • enqueue 方法会更新队列的 putIndex 和 count,并唤醒等待 notEmpty 条件的消费者线程

  • 4、释放锁:

    • 在 finally 块中释放锁,确保锁一定会被释放,避免死锁


3、enqueue 方法的源码分析

enqueue 是 put 方法中用于实际插入元素的私有方法。以下是其源码:


关键点解析

  • 1、插入元素:

    • 将元素 x 放入数组的 putIndex 位置

    • putIndex 是下一个插入元素的位置

  • 2、更新 putIndex:

    • 如果 putIndex 达到数组长度,将其重置为 0,实现循环数组的效果
  • 3、更新元素数量:

    • count 表示队列中的元素数量,插入成功后递增
  • 4、唤醒消费者线程:

    • 调用 notEmpty.signal() 唤醒等待 notEmpty 条件的消费者线程


4、put 方法的阻塞机制


put 方法的阻塞行为是通过 Condition 的 await() 方法实现的。以下是其工作原理:


1、队列满时的阻塞:

  • 如果队列满,当前线程会调用 notFull.await(),释放锁并进入等待状态

  • 线程会被加入到 notFull 条件的等待队列中


2、被唤醒的条件:

  • 当消费者线程从队列中移除一个元素时,会调用 notFull.signal() 或 notFull.signalAll(),唤醒等待 notFull 条件的生产者线程

  • 被唤醒的线程会重新尝试获取锁,并检查队列是否仍然满


3、中断处理::

  • 如果线程在等待期间被中断,await() 方法会抛出 InterruptedException,并清除中断状态


5、put 方法的性能优化


1、循环数组:

  • ArrayBlockingQueue 使用循环数组存储元素,避免了数组的频繁扩容和数据拷贝

  • 通过 putIndex 和 takeIndex 实现队列的循环利用


2、锁分离:

  • 使用单独的 Condition 对象(notFull 和 notEmpty)分别管理生产者和消费者的等待队列,减少锁竞争


3、公平性:

  • 可以通过构造函数指定是否使用公平锁。公平锁会按照线程等待的顺序分配锁,避免线程饥饿。


二、总结

ArrayBlockingQueue 的 put 方法通过以下机制实现了线程安全的阻塞插入:

1、锁机制:使用 ReentrantLock 保证线程安全。

2、条件变量:使用 notFull 和 notEmpty 管理线程的等待和唤醒。

3、循环数组:通过循环数组高效管理队列元素。

posted @ 2025-02-18 23:55  jock_javaEE  阅读(36)  评论(0)    收藏  举报