ArrayBlockingQueue源码解析

ArrayBlockingQueue是Java中的一个阻塞队列,基于数组实现,使用ReentrantLock来保证线程安全。文章列举了其常用方法,如add、offer、put等入队操作,以及remove、poll、take等出队操作,并提供了使用示例,展示了在队列满或空时的不同行为。此外,还分析了部分源码,解释了队列满或空时如何处理阻塞和唤醒机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayBlockingQueue底层使用了一个数组来实现队列,阻塞的实现使用了ReentrantLock

常用的方法

1、入队操作

  • add(E): 如果满了,扔异常,数据丢弃

  • offer(E): 入队成功返回true,入队失败返回false,数据被丢弃

  • put(E): 入队失败线程挂起,直到入队成功

  • offer(E,time,unit): 入队失败线程等待指定时间返回false,数据丢弃

2、出队操作

  • remove():出队失败抛出异常

  • poll():出队失败返回null

  • take():出队失败一直挂起,直到有元素出队

  • poll(time,unit):出队失败等待指定时间后返回null

使用案例

package com.zjw.juc;

import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ArrayBlockingQueueDemo {
  public static void main(String[] args) throws Exception {
    // capacity为数组长度,同时也是队列长度
    ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);

    for (; ; ) {
      Scanner scanner = new Scanner(System.in);
      String command = scanner.nextLine().trim();
      if ("exit".equals(command) || "quit".equals(command)) {
        break;
      }
      String[] commands = command.split("\\s+");
      switch (commands[0]) {
        case "add":
          try {
            queue.add(commands[1]);
          } catch (Exception e) {
            System.out.println("当队列满时抛出异常: " + e.getMessage());
          }
          break;
        case "offer":
          if (commands.length == 3) {
            boolean ret = queue.offer(commands[1], Integer.parseInt(commands[2]), TimeUnit.MILLISECONDS);
            if (!ret) {
              System.out.println("队列满,间隔" + commands[2] + "ms之后返回");
            }
          } else {
            boolean ret = queue.offer(commands[1]);
            if (!ret) {
              System.out.println("队列满,返回 false");
            } else {
              System.out.println("队列未满,返回 true");
            }
          }
          break;
        case "put":
          System.out.println("put 当队列满时会一直阻塞,直到放入数据成功.");
          queue.put(commands[1]);
          break;
        case "remove":
          if (commands.length == 2) {
            boolean ret = queue.remove(commands[1]);
            System.out.println("删除" + commands[1] + "元素返回结果: " + ret);
          } else {
            try {
              queue.remove();
            } catch (Exception e) {
              System.out.println("删除数据失败,抛出异常: " + e.getMessage());
            }
          }
          break;
        case "poll":
          if (commands.length == 2) {
            String ret = queue.poll(Integer.parseInt(commands[1]), TimeUnit.MILLISECONDS);
            if (ret == null) {
              System.out.println("队列为空,阻塞" + commands[1] + "ms后返回null");
            }
          } else {
            String ret = queue.poll();
            System.out.println("poll 返回: " + ret);
          }
          break;
        case "take":
          System.out.println("take操作当队列没有数据时会一直阻塞.");
          queue.take();
          break;
      }
      System.out.println(Arrays.asList(queue.toArray()));

    }
  }
}

源码分析

add(E)
public boolean add(E e) {
	// 调用super(AbstractQueue)的add方法 
  return super.add(e);
}

public boolean add(E e) {
	// 直接调用offer方法,如果offer调用成功直接返回true,否则抛异常
  if (offer(e))
    return true;
  else
    throw new IllegalStateException("Queue full");
}

public boolean offer(E e) {
	// 检查元素是否为null,如果为null直接抛异常
  checkNotNull(e);
  // 获取ReentrantLock,并加锁
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
  	// 队列满,返回false
    if (count == items.length)
      return false;
    else {
    	// 入队操作
      enqueue(e);
      return true;
    }
  } finally {
  	// 释放ReentrantLock
    lock.unlock();
  }
}

private void enqueue(E x) {
  final Object[] items = this.items;
  // 入队
  items[putIndex] = x;
  // 对齐游标,可以思考为循环队列 putIndex = (putIndex + 1) % items.length
  if (++putIndex == items.length)
    putIndex = 0;
  count++;
  // 唤醒因为队列空而阻塞的线程
  notEmpty.signal();
}
offer(E)
public boolean offer(E e) {
	// 检查元素是否为null,如果为null直接抛异常
  checkNotNull(e);
  // 获取ReentrantLock,并加锁
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
  	// 队列满,返回false
    if (count == items.length)
      return false;
    else {
    	// 入队操作
      enqueue(e);
      return true;
    }
  } finally {
  	// 释放ReentrantLock
    lock.unlock();
  }
}
offer(E, timeout, TimeUnit)
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
	// 检查元素不能为null,为null会跑出异常NullPointerException
  checkNotNull(e);
  long nanos = unit.toNanos(timeout);
  // 获取可中断锁
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
  	// 指定有限时间等待,时间到了会自动醒过来进行循环判断,最终会使nanos<=0条件成立,返回false
    while (count == items.length) {
      if (nanos <= 0)
        return false;
      nanos = notFull.awaitNanos(nanos);
    }
    // 元素入队
    enqueue(e);
    return true;
  } finally {
  	// 释放锁
    lock.unlock();
  }
}
put(E)
public void put(E e) throws InterruptedException {
	// 检查元素不能为null,为null会跑出异常NullPointerException
  checkNotNull(e);
  // 获取可中断锁
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
  	// 如果队列满了,会一直等待,直到被唤醒
    while (count == items.length)
      notFull.await();
    // 入队操作
    enqueue(e);
  } finally {
    lock.unlock();
  }
}
remove()
public E remove() {
	// 调用poll获取元素,如果没有获取到跑出异常NoSuchElementException
  E x = poll();
  if (x != null)
    return x; // 获取到了直接返回
  else
    throw new NoSuchElementException();
}
poll()
public E poll() {
	// 加锁
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
  	// 如果队列空返回null,否则进行出队操作,并返回出队结果
    return (count == 0) ? null : dequeue();
  } finally {
  	// 释放锁
    lock.unlock();
  }
}

private E dequeue() {
  final Object[] items = this.items;
  // 获取take的数据
  E x = (E) items[takeIndex];
  // 擦除数据,防止误操作越界读取到数据,同时可以帮助GC
  items[takeIndex] = null;
  // takeIndex的对齐操作 takeIndex = (takeIndex + 1) % items.length
  if (++takeIndex == items.length)
    takeIndex = 0;
  // 队列元素--
  count--;
  // 迭代器相关操作
  if (itrs != null)
    itrs.elementDequeued();
  // 唤醒因为入队操作阻塞的线程
  notFull.signal();
  return x;
}
take()
public E take() throws InterruptedException {
	// 获取可中断锁
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
  	// 如果队列空,则进入等待
    while (count == 0)
      notEmpty.await();
    // 出队操作
    return dequeue();
  } finally {
  	// 释放锁
    lock.unlock();
  }
}
poll(time, unit)
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
	// 时间转换
  long nanos = unit.toNanos(timeout);
  // 获取可中断锁
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
  	// 如果队列空则等待指定时间之后返回,如果后一次循环检查nanos<0 则会直接返回null,不会走到dequeue()
    while (count == 0) {
      if (nanos <= 0)
        return null;
      nanos = notEmpty.awaitNanos(nanos);
    }
    // 出队操作
    return dequeue();
  } finally {
    lock.unlock();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值