262. Java 集合 - Java 中 ArrayList 与 LinkedList 读取元素性能大对决

文章目录

  • [262. Java 集合 - Java 中 ArrayList 与 LinkedList 读取元素性能大对决](#262. Java 集合 - Java 中 ArrayList 与 LinkedList 读取元素性能大对决)
      • [🧪 Benchmark 场景简介](#🧪 Benchmark 场景简介)
      • [⚙️ 测试代码简化展示](#⚙️ 测试代码简化展示)
      • [📊 基准测试结果总结](#📊 基准测试结果总结)
        • [✅ 读取第一个元素](#✅ 读取第一个元素)
        • [✅ 读取最后一个元素](#✅ 读取最后一个元素)
        • [⚠️ 读取中间元素](#⚠️ 读取中间元素)
      • [🧠 为什么 `LinkedList` 慢?](#🧠 为什么 LinkedList 慢?)
        • [🔍 内部结构回顾:](#🔍 内部结构回顾:)
      • [💣 Pointer Chasing & Cache Miss 示例](#💣 Pointer Chasing & Cache Miss 示例)
      • [📌 总结:读取操作谁更强?](#📌 总结:读取操作谁更强?)
      • [✅ 小贴士](#✅ 小贴士)

262. Java 集合 - Java 中 ArrayList 与 LinkedList 读取元素性能大对决

在 Java 中,我们经常面对一个问题:

🔍 哪个更适合:ArrayList 还是 LinkedList

这节我们以"读取元素"为例,用基准测试(benchmark)对两者进行深入比较。


🧪 Benchmark 场景简介

我们将对以下三种读取操作进行性能测试(使用 JMH 工具):

  1. 读取第一个元素list.get(0)
  2. 读取最后一个元素list.get(list.size() - 1)
  3. 读取中间的元素list.get(list.size() / 2)

我们对 ArrayListLinkedList 分别执行这些操作,并使用不同的列表大小进行测试。


⚙️ 测试代码简化展示

java 复制代码
List<Integer> ints = ...; // 已填充好数据
int last = ints.size() - 1;
int middle = ints.size() / 2;

ints.get(0);       // 读取第一个元素
ints.get(last);    // 读取最后一个元素
ints.get(middle);  // 读取中间元素

📊 基准测试结果总结

✅ 读取第一个元素
List 类型 Size=10 Size=100 Size=1,000 Size=10,000
ArrayList 1.18 ns 1.20 ns 1.17 ns 1.17 ns
LinkedList 1.12 ns 1.11 ns 1.12 ns 1.11 ns

👉 两者性能几乎相同。读取第一个元素是 O(1) 操作,和数据规模无关。


✅ 读取最后一个元素
List 类型 Size=10 Size=100 Size=1,000 Size=10,000
ArrayList 1.25 ns 1.23 ns 1.24 ns 1.25 ns
LinkedList 1.49 ns 1.46 ns 1.47 ns 1.48 ns

🔎 LinkedList 多了一点开销(虽然很小),但仍是 O(1),因为它有一个指向末尾的引用。


⚠️ 读取中间元素
List 类型 Size=10 Size=100 Size=1,000 Size=10,000
ArrayList 1.57 ns 1.61 ns 1.54 ns 1.53 ns
LinkedList 3.21 ns 31.11 ns 566.07 ns 7,836.10 ns

🔥 注意 LinkedList 的性能急剧下降 !这说明读取中间元素是 O(n) 操作 ------ 因为它需要顺着指针走一遍。


🧠 为什么 LinkedList 慢?

🔍 内部结构回顾:
java 复制代码
Node {
   E element;
   Node next;
   Node previous;
}
  • LinkedList双向链表
  • LinkedList 类保存两个指针:firstlast
  • 读取中间元素时必须逐个节点遍历,即"指针追踪(pointer chasing)"。

💣 Pointer Chasing & Cache Miss 示例

我们用以下代码构造更"稀疏"的链表,以人为制造 cache miss 的情况:

java 复制代码
LinkedList<Integer> ints = new LinkedList<>();
LinkedList<Integer> intsOther = new LinkedList<>();

for (int i = 0; i < LIST_SIZE; i++) {
    ints.add(i);
    for (int k = 0; k < SPARSE_INDEX; k++) {
        intsOther.add(k); // 插入无用节点,制造内存间隔
    }
}
SPARSE_INDEX 读取中间元素耗时
0 561 ns
1 602 ns
10 944 ns
100 1509 ns

➡️ 节点之间不连续,会大大降低性能。


📌 总结:读取操作谁更强?

场景 推荐使用
读取头或尾 都可以
读取中间元素 ArrayList
遍历整张表 ArrayList 更快(使用索引或增强 for 循环)

✅ 小贴士

  • 🚀 使用 JMH 进行性能测试,避免误导的微基准。
  • 📦 ArrayList 底层是数组,支持随机访问,性能稳定。
  • 🔄 LinkedList 更适合频繁插入/删除操作(尤其在头部)。
相关推荐
优橙教育8 分钟前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
SeaTunnel2 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
碎光拾影2 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Marst Code3 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
Miao121313 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
腻害兔3 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:支付模块 yudao-module-pay,一个让产品经理都看懂的支付中台设计
java·前端·vue.js·产品经理·ai编程
CRMEB系统商城4 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience5 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
我的xiaodoujiao6 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具