

1. 为什么需要 List?
在 Redis 的五大基本类型中,List(列表) 是用来存储有序的、可重复的 字符串集合。它和 Java 中的 LinkedList 或 Python 中的 list 类似,但 Redis 的 List 是经过特殊设计的,能在头部和尾部进行高效的操作。
典型场景:
-
消息队列(生产者/消费者)
-
最新消息列表(比如微博时间线)
-
栈(后进先出)或队列(先进先出)
List 的有序性体现在每个元素都有一个下标(索引),从 0 开始计数(也可以负数表示倒数第几个),你可以通过索引访问任意位置的元素。
2. List 的核心概念
-
元素有序:插入顺序决定了元素的存储顺序。
-
元素可重复:同一个值可以出现多次。
-
双向操作:从左边(头部)或右边(尾部)插入/弹出元素都非常快(O(1))。
-
支持索引访问 :通过
LINDEX或LRANGE获取指定范围的元素。
一个 List 最多可以容纳 2^32 - 1(约 42 亿)个元素,绝大多数场景够用了。
3. 常用命令详解
我们从最基础的「增删改查」开始,一步步深入。

3.1 插入元素
LPUSH -- 从左侧插入(头插)
LPUSH key element [element ...]
-
将一个或多个元素从左边插入列表(可以理解为"头插")。
-
返回插入后列表的长度。
-
时间复杂度 O(N),N 为插入元素个数(但对于单个元素是 O(1))。

所以多次 LPUSH 后,列表是"后来的在前"。
RPUSH -- 从右侧插入(尾插)
RPUSH key element [element ...]
- 从右边插入(尾插),同样返回新长度。

LPUSHX / RPUSHX -- 仅当 key 存在时插入
这两个命令与
LPUSH/RPUSH类似,但只在 key 已存在时执行,如果 key 不存在,则什么也不做

3.2 弹出元素
LPOP -- 从左侧弹出(头删)
LPOP key
-
移除并返回列表最左边的元素(头元素)。
-
如果列表为空,返回
nil。

RPOP -- 从右侧弹出(尾删)
RPOP -- 从右侧弹出(尾删)
- 移除并返回最右边的元素。

LPOP和RPOP都是 O(1) 操作,非常高效。
3.3 获取范围/索引
LRANGE -- 获取指定范围的元素
LRANGE key start stop
-
返回从
start到stop的所有元素(闭区间,包含两端)。 -
start/stop支持负数索引:-1 代表最后一个元素,-2 代表倒数第二个,以此类推。 -
如果
start大于实际长度,返回空列表;如果stop超出范围,只返回存在的部分。

注意:LRANGE 的时间复杂度是 O(N),N 是返回的元素个数。对于大列表,不建议取太大的范围。
LINDEX -- 获取指定索引位置的元素
LINDEX key index
-
返回索引
index处的元素,支持负数(-1 为最后一个)。 -
如果索引超出范围,返回
nil。

3.4 获取列表长度
LLEN
LLEN key
- 返回列表的长度(元素个数)。O(1) 操作。

3.5 删除元素
LREM -- 移除指定个数的特定元素
LREM key count element
-
从列表中移除前
count个 值为element的元素。 -
count > 0:从左向右移除最多count个。 -
count < 0:从右向左移除最多|count|个。 -
count = 0:移除所有值为element的元素。
- 返回实际移除的个数。

注意:LREM 的时间复杂度为 O(N),N 是列表长度,因为它需要遍历。
3.6 插入到指定元素前后
LINSERT -- 在某个元素前/后插入
LINSERT key BEFORE|AFTER pivot element
-
在列表中,在第一个值为
pivot的元素之前 或之后 插入element。 -
如果
pivot不存在,则返回 -1 且不做插入。 -
返回插入后列表的长度。

3.7 设置指定索引的值
LSET -- 修改指定位置的元素
LSET key index value
-
将索引
index处的元素设置为value。 -
如果索引超出范围,返回错误。
-
O(N) 操作(N 为列表长度,因为底层可能是链表)。

3.8 修剪列表
LTRIM -- 只保留指定范围的元素
LTRIM key start stop
-
保留
[start, stop]范围内的元素,其余全部删除。 -
可以用于限制列表大小(比如只保留最近 100 条消息)。

4. 阻塞版本命令
Redis 提供了 阻塞式 的弹出命令:BLPOP 和 BRPOP。
BLPOP / BRPOP
BLPOP key [key ...] timeout
BRPOP key [key ...] timeout
-
如果指定的列表中至少有一个非空 ,则立即从左/右弹出第一个元素,类似
LPOP/RPOP。 -
如果所有列表都为空,则阻塞等待,直到有元素可弹或超时。
-
timeout为超时时间(秒),如果设为0表示永远阻塞。 -
支持检查多个 key,从左到右扫描,哪个 key 有元素就弹出哪个。

使用场景 :生产者-消费者模式 。生产者 RPUSH 元素,消费者 BLPOP 阻塞等待,实现一个简单的消息队列。



注意:阻塞版本允许多个消费者同时阻塞在同一个队列上,当有元素时,只有一个消费者能抢到(公平竞争)。
5. 内部编码
Redis 的 List 内部实现会根据元素数量和大小自动选择编码:
-
ziplist(压缩列表) :当列表元素个数 <
list-max-ziplist-entries(默认 512)且所有元素长度 <list-max-ziplist-value(默认 64 字节)时使用。节省内存,但读写较大时性能下降。 -
quicklist(快速列表) :从 Redis 3.2 开始,list 统一采用
quicklist作为内部编码,它是一个双向链表,每个节点是一个 ziplist,兼顾了内存和性能。
你可以用 OBJECT ENCODING key 查看:
127.0.0.1:6379> OBJECT ENCODING mylist
"quicklist"
大多数情况下,你无需关心底层编码,Redis 会自动优化。