一、复盘面试
遇到面试问到:如果我想在redis实现队列,会用到哪个命令?根据redis手册关于Redis 列表(List) 命令主要操作有四种非阻塞版lpush/lpop/rpush/rpop,两种阻塞版本blpop/brpop,l和r代表左(left)和右(right)缩写,push代表添加也叫压入,pop代表弹出。基本满足先进入先出(FIFO)效果就完成了基本的队列,本次GitHub实验代码仓库。
通过命令模拟队列
RDM Redis Console
连接中...
已连接。
localhost:0>lpush mylist a b c d
"4"
localhost:0>rpop mylist
"a"
localhost:0>rpop mylist
"b"
localhost:0>rpop mylist
"c"
localhost:0>rpop mylist
"d"
localhost:0>rpop mylist
null
localhost:0>
复制代码
二、java模拟队列实现生产者消费者模式
redis配置常量
package io.charles;
public class Constant {
/**
* redis链接地址
*/
public static final String host = "127.0.0.1";
/**
* redis启动端口
*/
public static final int port = 6379;
/**
* 正式队列列表名称
*/
public static final String task_queue = "task-queue";
/**
* 临时队列列表名称
*/
public static final String tmp_queue = "tmp-queue";
}
复制代码
TaskProducer模拟生产者
package io.charles;
/**
* 用于模拟生产者
*/
import java.util.Random;
import java.util.UUID;
import redis.clients.jedis.Jedis;
public class TaskProducer implements Runnable {
Jedis jedis = new Jedis(Constant.host, Constant.port);
public void run() {
Random random = new Random();
while (true) {
try {
Thread.sleep(random.nextInt(600) + 600);
// 模拟生成一个任务
UUID taskid = UUID.randomUUID();
//将任务插入任务队列:task-queue
jedis.lpush(Constant.task_queue, taskid.toString());
System.out.println("插入了一个新的任务: " + taskid);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
复制代码
TaskConsumer模拟消费者
package io.charles;
import java.util.Random;
import redis.clients.jedis.Jedis;
/**
* 模拟消费者
*/
public class TaskConsumer implements Runnable {
Jedis jedis = new Jedis(Constant.host, Constant.port);
public void run() {
Random random = new Random();
while (true) {
//从任务队列"task-queue"中获取一个任务,并将该任务放入临时队列"tmp-queue"
String taskid = jedis.rpoplpush(Constant.task_queue, Constant.tmp_queue);
// 模拟一下:睡觉
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟成功和失败的偶然现象
if (random.nextInt(13) % 7 == 0) {// 模拟失败的情况,概率为2/13
//将本次处理失败的任务从临时队列"tmp-queue"中,弹回任务队列"task-queue"
jedis.rpoplpush(Constant.task_queue, Constant.tmp_queue);
System.out.println(taskid + "处理失败,被弹回任务队列");
} else {// 模拟成功的情况
// 将本次任务从临时队列"tmp-queue"中清除
jedis.rpop(Constant.tmp_queue);
System.out.println(taskid + "处理成功,被清除");
}
}
}
}
复制代码
TaskShedulerSystem启动生产者和消费者线程
package io.charles;
public class TaskShedulerSystem {
public static void main(String[] args) throws Exception {
// 启动一个生产者线程,模拟任务的产生
new Thread(new TaskProducer()).start();
Thread.sleep(15000);
//启动一个线程者线程,模拟任务的处理
new Thread(new TaskConsumer()).start();
}
}
复制代码
三、参考资料