1. 概述
本文将快速介绍 Big Queue,这是一个基于 Java 实现的持久化队列(persistent queue)。
我们会简要分析它的架构设计,并通过几个简单但实用的代码示例,带你快速上手使用。如果你正在寻找一个轻量、高效、能处理海量数据的本地队列方案,Big Queue 是一个值得考虑的选择。
2. 使用方式
首先,在项目中引入 bigqueue
依赖:
<dependency>
<groupId>com.leansoft</groupId>
<artifactId>bigqueue</artifactId>
<version>0.7.0</version>
</dependency>
同时需要添加其专属仓库(因为未发布到中央仓库):
<repository>
<id>github.release.repo</id>
<url>https://raw.github.com/bulldog2011/bulldog-repo/master/repo/releases/</url>
</repository>
✅ 提示:这个库虽然小众,但 API 设计非常简洁,如果你熟悉 Java 的基础队列操作,几乎可以无缝切换。
2.1 初始化
通过构造函数即可创建一个 Big Queue 实例:
@Before
public void setup() {
String queueDir = System.getProperty("user.home");
String queueName = "baeldung-queue";
bigQueue = new BigQueueImpl(queueDir, queueName);
}
queueDir
:队列数据的存储根目录queueName
:队列名称,会在此目录下生成一个同名文件夹用于持久化数据
⚠️ 重要:使用完毕后务必调用 close()
方法释放资源,避免内存泄漏或文件句柄未释放:
bigQueue.close();
2.2 插入元素
使用 enqueue
方法将数据写入队尾:
@Test
public void whenAddingRecords_ThenTheSizeIsCorrect() {
for (int i = 1; i <= 100; i++) {
bigQueue.enqueue(String.valueOf(i).getBytes());
}
assertEquals(100, bigQueue.size());
}
⚠️ 踩坑提醒:Big Queue 只支持 byte[]
类型!
这意味着你需要自己负责对象的序列化(如 JSON、Protobuf、Kryo 等),插入前转成字节数组。
2.3 读取元素
使用 dequeue
方法从队头取出并移除元素:
@Test
public void whenAddingRecords_ThenTheyCanBeRetrieved() {
bigQueue.enqueue(String.valueOf("new_record").getBytes());
String record = new String(bigQueue.dequeue());
assertEquals("new_record", record);
}
同样,取出后需要手动反序列化。
❌ 注意:从空队列中 dequeue
会抛出 NullPointerException
,不是 NoSuchElementException
,这点和标准队列不同!
✅ 安全做法是先判断是否为空:
if (!bigQueue.isEmpty()) {
byte[] data = bigQueue.dequeue();
// 处理数据
}
✅ 如果想清空整个队列而不逐个消费,可以直接调用:
bigQueue.removeAll();
简单粗暴,适合做重置操作。
2.4 查看队首元素(Peek)
peek
方法可以查看队头元素但不移除它,适合做预判处理:
@Test
public void whenPeekingRecords_ThenSizeDoesntChange() {
for (int i = 1; i <= 100; i++) {
bigQueue.enqueue(String.valueOf(i).getBytes());
}
String firstRecord = new String(bigQueue.peek());
assertEquals("1", firstRecord);
assertEquals(100, bigQueue.size()); // 队列长度不变
}
2.5 清理已消费的数据
⚠️ 关键机制:调用 dequeue
后,数据虽然从逻辑上被“消费”,但物理上仍保留在磁盘中!
这会导致磁盘空间持续增长,必须手动触发垃圾回收:
bigQueue.gc();
✅ 这个 gc()
方法就像 JVM 的垃圾回收器一样,会清理掉已经被消费的旧记录,释放磁盘空间。
建议在批量消费后定期调用,避免“磁盘爆炸”。
3. 架构与特性
Big Queue 最令人惊讶的一点是:整个核心代码只有 12 个源文件,约 20KB,却实现了高性能的持久化队列。
它本质上是一个基于内存映射文件(memory-mapped file)实现的磁盘队列,兼顾了速度与容量。
3.1 支持超大数据量
- ✅ 队列大小仅受限于磁盘空间,理论上可无限扩展(加硬盘就行),这也是“Big”名字的由来。
- 所有数据持久化到磁盘,进程崩溃后不丢消息。
- 性能瓶颈主要在磁盘 I/O,因此强烈建议使用 SSD。
3.2 极致的读取速度
底层使用 memory-mapped file,将文件映射到虚拟内存。
队列头部(可访问部分)常驻内存,访问延迟极低。
✅ 即使队列达到 TB 级别,读取时间复杂度依然是 **O(1)**!
💡 原理类比:就像 mmap 读文件比传统 IO 快很多,这里也是同理。
3.3 优势总结
- ✅ 无限扩展:只要磁盘够,队列就无限大
- ✅ 高性能:在普通机器上,多线程吞吐可达 166MB/s
- 若每条消息 1KB,则每秒处理约 16.6 万条
- 单线程下甚至可达 33.3 万条/秒,性能非常可观
- ✅ 轻量级:代码极少,无复杂依赖,易于嵌入
- ✅ 持久化保障:断电不丢数据
3.4 局限性
- ❌ 需手动 GC:已消费数据不会自动删除,必须显式调用
gc()
,否则磁盘会越用越多 - ❌ 无自动序列化:所有数据必须手动转为
byte[]
,对使用者要求更高 - ❌ 功能单一:只支持基础队列操作,不支持优先级、延迟、广播等高级特性
4. 总结
Big Queue 是一个极简但高效的持久化队列实现,特别适合以下场景:
- 需要本地持久化缓冲大量数据
- 对读写性能有一定要求
- 不想引入 Kafka、RabbitMQ 等重型中间件
虽然功能简单,但在合适场景下能发挥巨大价值。
对于轻量级、高性能、本地化的队列需求,它是一个被低估的“小钢炮”工具。
示例代码已上传至 GitHub:https://github.com/baeldung/tutorials/tree/master/data-structures