👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中... 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
📚欢迎订阅专栏,专栏名《在2B工作中寻求并发是否搞错了什么》
前言
你是否在线程池工具类里看到过它的身影?
java
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
你是否会好奇LinkedBlockingQueue是啥呢?
没有关系,小手手点上关注,跟上主播的节奏。
什么是LinkedBlockingQueue?
LinkedBlockingQueue 是一个基于链表的线程安全阻塞队列,常用于生产者-消费者模式。
数据结构:
- 基于单向链表实现,队列头尾分别通过 head 和 last 指针维护。
- 默认容量为 Integer.MAX_VALUE(近似无界队列),但可手动指定固定容量。
线程安全
- 使用两把锁分离设计(入队锁 putLock 和出队锁 takeLock),提高并发性能。
- 通过 ReentrantLock 和 Condition 实现阻塞(队列空时阻塞消费者,队列满时阻塞生产者)。
阻塞操作
- put():队列满时阻塞生产者线程。
- take():队列空时阻塞消费者线程。
- 非阻塞方法:offer()(失败返回 false)、poll()(失败返回 null)
简单说说,和我们之前说的ArrayBlokcingQueue的区别:
特性 | LinkedBlockingQueue | ArrayBlockingQueue |
---|---|---|
底层结构 | 链表 | 数组 |
默认容量 | Integer.MAX_VALUE(无界) | 必须显式指定 |
锁机制 | 双锁分离(更高并发) | 单锁控制 |
内存占用 | 动态扩展(链表节点开销) | 预分配连续内存 |
简单使用LinkedBlockingQueue
因为我们的LinkedBlockingQueue也是实现了BlockingQueue的接口,所以下面的代码例子,会有这些方法。

构造方法
首先从构造方法说起吧,LinkedBlockingQueue有3个构造方法:
java
// 没有传任何参数,默认容量大小为Integer.MAX_VALUE
public LinkedBlockingQueue();
// 容量大小为入参
public LinkedBlockingQueue(int capacity)
// 容量大小为Integer.MAX_VALUE,集合中初始化元素为c
public LinkedBlockingQueue(Collection<? extends E> c)
添加元素入队操作
add(E e)方法 :简单粗暴,非阻塞添加元素,队列满了的话直接抛IllegalStateException
异常。
java
public static void main(String[] args) {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
queue.add("A");
queue.add("B"); // Exception in thread "main" java.lang.IllegalStateException: Queue full
}
offer(E e)方法:非阻塞添加元素,成功返回boolean,添加成功为true,添加失败为false
java
public static void main(String[] args) {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
boolean result = queue.offer("A"); // true
System.out.println(result);
result = queue.offer("B"); // false
System.out.println(result);
}
offer(E e, long timeout, TimeUnit unit)方法: 向队列添加元素。如果队列满了,就阻塞线程,等待一段时间,一段时间过后队列还是满的话,意味添加元素失败返回false,否则返回true。
ini
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // true
System.out.println(result);
result = queue.offer("B", 1, TimeUnit.SECONDS); // false
System.out.println(result);
}
但如果我们这样等待一会的话,执行结果就会不一样:
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // true
System.out.println(result);
// 启动另一个生产者线程
new Thread(() -> {
Boolean res;
try {
res = queue.offer("B", 2, TimeUnit.SECONDS); // 队列满了,阻塞2s等待
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(res); // true
}).start();
// 移除队列中的元素
queue.poll();
}
put(E e)方法: 阻塞线程,直到队列不为空或中断者线程。
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
queue.put("A");
queue.put("B"); // 队列已满,线程阻塞在这
}
移除元素出队操作
remove()方法:如果队列为空,直接抛出NoSuchElementException
异常。
java
public static void main(String[] args) {
BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);
queue.remove(); // Exception in thread "main" java.util.NoSuchElementException
}
poll()方法:非阻塞获取队列头元素,如果队列为空,直接返回null。
java
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);
String poll = queue.poll();
System.out.println(poll); // null(队列中没有元素)
queue.offer("A"); // 向队列中添加元素
poll= queue.poll();
System.out.println(poll); // A
}
poll(long timeout, TimeUnit unit)方法:阻塞一段时间获取队列中的元素,如果超过时间了,就队列还是为空,就返回null。
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);
// 创建一个线程,3s后生产1个元素到队列中
new Thread(() -> {
try {
Thread.sleep(2000);
queue.offer("A");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 消费者,阻塞5s获取元素
String poll= queue.poll(5 , TimeUnit.SECONDS);
System.out.println(poll); // A
}
take()方法:阻塞线程获取队列中的元素,直到队列不为空,或者被其他线程中断,抛出异常停止。
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);
// 创建一个消费者线程,获取队列中的元素
Thread consumerThread = new Thread(() -> {
try {
String take = queue.take(); // 在这个案例中,线程会被一直阻塞到这,直到被中断
System.out.println("消费者线程获取到元素:" + take);
} catch (InterruptedException e) {
System.out.println("线程者线程被中断了");
}
});
consumerThread.start();
// 隔3s后,中断消费者线程
TimeUnit.SECONDS.sleep(1);
consumerThread.interrupt();
}
输出结果:
线程者线程被中断了
检查队列中的元素
element()
方法: 返回队列头的元素,但是如果队列为空,element
方法会抛出NoSuchElementException
异常。
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
queue.offer("A");
queue.offer("B");
System.out.println(queue.element()); // A
queue.poll(); // 头元素出队
System.out.println(queue.element()); // B
}
// 异常的情况
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
String element = queue.element(); // Exception in thread "main" java.util.NoSuchElementException
}
peek()
方法 :和element()
方法差不多,返回队列头的元素,如果队列为空,会返回null
。
java
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);
String element = queue.peek();
System.out.println(element); // null
}
后话
这就结束了?没有的,宝贝,没有的。
这里只是简答的使用,小手手点上关注,主播下一篇,直接开始看LinkedBlockingQueue源码。