写点什么

阻塞队列实现原理

作者:周杰伦本人
  • 2022 年 6 月 03 日
  • 本文字数:1084 字

    阅读完需:约 4 分钟

14 阻塞队列实现原理

如果队列是空的,消费者会一直等待,当生产者添加元素时,消费者是如何知道当前队列有元素的呢?如果让你来设计阻塞队列你会如何设计,如何让生产者和消费者进行高效率的通信呢?让我们先来看看 JDK 是如何实现的。


使用通知模式实现。


所谓通知模式,就是当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。通过查看 JDK 源码发现 ArrayBlockingQueue 使用了 Condition 来实现。


当往队列里插入一个元素时,如果队列不可用,那么阻塞生产者主要通过 LockSupport.park(this)来实现。


public final void await() throws InterruptedException {    if (Thread.interrupted())        throw new InterruptedException();    Node node = addConditionWaiter();    int savedState = fullyRelease(node);    int interruptMode = 0;    while (!isOnSyncQueue(node)) {        LockSupport.park(this);        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)            break;    }    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)        interruptMode = REINTERRUPT;    if (node.nextWaiter != null) // clean up if cancelled        unlinkCancelledWaiters();    if (interruptMode != 0)        reportInterruptAfterWait(interruptMode);}
复制代码


public static void park(Object blocker) {    Thread t = Thread.currentThread();    setBlocker(t, blocker);    UNSAFE.park(false, 0L);    setBlocker(t, null);}
复制代码


继续进入源码,发现调用 setBlocker 先保存一下将要阻塞的线程,然后调用 unsafe.park 阻塞当前线程。


private static void setBlocker(Thread t, Object arg) {    // Even though volatile, hotspot doesn't need a write barrier here.    UNSAFE.putObject(t, parkBlockerOffset, arg);}
复制代码


unsafe.park 是个 native 方法


public native void putObject(Object var1, long var2, Object var4);
复制代码


park 这个方法会阻塞当前线程,只有以下 4 种情况中的一种发生时,该方法才会返回。


  • 与 park 对应的 unpark 执行或已经执行时。“已经执行”是指 unpark 先执行,然后再执行 park 的情况。

  • 线程被中断时。

  • 等待完 time 参数指定的毫秒数时。

  • 异常现象发生时,这个异常现象没有任何原因。


当线程被阻塞队列阻塞时,线程会进入 WAITING(parking)状态。

总结

阻塞队列的实现原理是就是利用了通知模式,当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用

发布于: 刚刚阅读数: 5
用户头像

还未添加个人签名 2020.02.29 加入

还未添加个人简介

评论

发布
暂无评论
阻塞队列实现原理_6月月更_周杰伦本人_InfoQ写作社区