源码|并发一枝花之BlockingQueue

本文深入探讨了Java并发编程中的 BlockingQueue,重点分析了LinkedBlockingQueue的实现细节,包括阻塞方法put()和take()的工作原理,以及与ArrayBlockingQueue的区别。通过源码分析,揭示了其在并发性能和线程安全方面的精妙设计。
摘要由CSDN通过智能技术生成

今天来介绍Java并发编程中最受欢迎的同步类——堪称并发一枝花之BlockingQueue。

JDK版本:oracle java 1.8.0_102

继续阅读之前,需确保你对锁和条件队列的使用方法烂熟于心,特别是条件队列,否则你可能无法理解以下源码的精妙之处,甚至基本的正确性。本篇暂不涉及此部分内容,需读者自行准备。

接口定义

BlockingQueue继承自Queue,增加了阻塞的入队、出队等特性:

public interface BlockingQueue<E> extends Queue<E> {
  boolean add(E e);
  void put(E e) throws InterruptedException;
  // can extends from Queue. i don't know why overriding here
  boolean offer(E e);
  boolean offer(E e, long timeout, TimeUnit unit)
      throws InterruptedException;
  E take() throws InterruptedException;
  // extends from Queue
  // E poll();
  E poll(long timeout, TimeUnit unit)
      throws InterruptedException;
  int remainingCapacity();
  boolean remove(Object o);
  public boolean contains(Object o);
  int drainTo(Collection<? super E> c);
  int drainTo(Collection<? super E> c, int maxElements);
}

为了方便讲解,我调整了部分方法的顺序,还增加了注释辅助说明。

需要关注的是两对方法:

  • 阻塞方法BlockingQueue#put()和BlockingQueue#take():如果入队(或出队,下同)失败(如希望入队但队列满,下同),则等待,一直到满足入队条件,入队成功。
  • 非阻塞方法BlockingQueue#offer()和BlockingQueue#poll(),及它们的超时版本:非超时版本是瞬时动作,如果入队当前入队失败,则立刻返回失败;超时版本可在此基础上阻塞一段时间,相当于限时的BlockingQueue#put()和BlockingQueue#take()。

实现类

BlockingQueue有很多实现类。根据github的code results排名,最常用的是LinkedBlockingQueue(253k)和ArrayBlockingQueue(95k)。LinkedBlockingQueue的性能在大部分情况下优于ArrayBlockingQueue,本文主要介绍LinkedBlockingQueue,文末会简要提及二者的对比。

LinkedBlockingQueue

阻塞方法put()和take()

两个阻塞方法相对简单,有助于理解LinkedBlockingQueue的核心思想:在队头和队尾各持有一把锁,入队和出队之间不存在竞争

前面在Java实现生产者-消费者模型中循序渐进的引出了BlockingQueue#put()和BlockingQueue#take()的实现,可以先去复习一下,了解为什么LinkedBlockingQueue要如此设计。以下是更细致的讲解。

阻塞的入队操作PUT()

在队尾入队。putLock和notFull配合完成同步。

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    int c = -1;
    Node<E> node = new Node<E>(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
        while (count.get() == capacity) {
            notFull.await();
        }
        enqueue(node);
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
}

现在触发一个入队操作,分情况讨论。

case1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值