list(双向链表)
list是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,可以在链表的左右两边分别操作(反向查找和遍历等),所以也称为“双向链表”,不过也带来了部分额外的内存开销,redis内部的很多实现,同时,如果是在链表的两头插入或删除,会非常高效,但是要是这些操作在链表的中间,那就比较低效了。
在插入时,若该key值不存在,redis将为该键创建一个新的链表。若链表中所有的元素都被移除,该键也会被数据库中删除。一个列表最多可以包含 232 - 1 个元素
常用命令
lpush,rpush,rpop,lrange,blpop(阻塞版)等
存入的形式
就是存放pre和next两个指针,以及节点的一些相关信息。每增加一个节点,重新分配一块内存。
list列表
从头部(左边)插入数据:lpush key v1 v2 v3
从尾部(右边)插入数据:rpush key v1 v2 v3
读取list中指定范围的values:lrange key start end
redis> lrange task-queue 0 -1 (-1表示读取整个list)
从头部弹出一个元素:lpop key
从尾部弹出一个元素:rpop key
从一个list的尾部弹出一个元素插入到另一个list:rpoplpush key1 key2
应用案例:任务调度系统
- 生产者不断产生任务,放入task-queue排队。
- 消费者不断拿出任务来处理,同时放入一个tmp-queue暂存,
如果任务处理成功,则清除tmp-queue;
如果任务处理失败,将任务弹回task-queue。
代码实现
A、生产者——模拟产生任务 public class TaskProducer { // 获取一个redis的客户端连接对象(这里我们用的是jedis) public static Jedis getRedisConnection(String host, int port) { Jedis jedis = new Jedis(host, port); return jedis; } public static void main(String[] args) { // redis服务器的ip地址和默认端口 Jedis jedis = getRedisConnection("192.168.2.70", 6379); // 随机数,这里用于间隔生产者任务的产生 Random random = new Random(); // 生成任务 while (true) { // 生成任务的速度有一定的随机性,在1-2秒之间 Thread.sleep(random.nextInt(1000) + 1000); // 生成一个任务 String taskid = UUID.randomUUID().toString(); // 往任务队列"task-queue"中插入,第一次插入时,"task-queue"还不存在 //但是lpush方法会在redis库中创建一条新的list数据 jedis.lpush("task-queue", taskid); System.out.println("向任务队列中插入了一个新的任务: " + taskid); } } } B、消费者——模拟处理任务,并且管理暂存队列 public class TaskConsumer { public static void main(String[] args) { Jedis jedis = new Jedis("192.168.2.70", 6379); Random random = new Random(); while (true) { // 从task-queue中取一个任务,同时放入"tmp-queue" String taskid = jedis.rpoplpush("task-queue", "tmp-queue"); // 模拟处理任务 Thread.sleep(1000); // 模拟有成功又有失败的情况 int nextInt = random.nextInt(13); if(nextInt % 7 == 0){ // 模拟失败的情况 // 失败的情况下,需要将任务从"tmp-queue"弹回"task-queue" jedis.rpoplpush("tmp-queue", "task-queue"); System.out.println("-------任务处理失败: " + taskid); }else{ // 模拟成功的情况 // 成功的情况下,将任务从"tmp-queue"清除 jedis.rpop("tmp-queue"); System.out.println("任务处理成功: " + taskid); } } } }