1,队列
@Slf4j @Component public class RedisMessageQueue { @Autowired private Jedis jedis; private String key = "redis-queue"; public RedisMessageQueue() { } private static final String SCRIPT = "local table = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2]);\n" + "\n" + "local key = table[1];\n" + "\n" + "if key == nil then\n" + "\treturn nil;\n" + "else\n" + "\tredis.call('ZREM', KEYS[1], key);\n" + "\treturn key;\n" + "end"; public void put(String message, long delayTime, TimeUnit unit) { long timeout = TimeUnit.MILLISECONDS.convert(delayTime, unit); jedis.zadd(key, Instant.now().toEpochMilli() + timeout, message); } public String poll() { List<String> argvs = Lists.newArrayList(); argvs.add("0"); argvs.add(String.valueOf(Instant.now().toEpochMilli())); Object result = jedis.eval(SCRIPT, Collections.singletonList(key), argvs); if (Objects.isNull(result)) { return null; } return String.valueOf(result); } }
lua脚本
local table = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2]); local key = table[1]; if key == nil then return nil; else redis.call('ZREM', KEYS[1], key); return key; end
2,消费者线程
@Slf4j public class LoggerWorker implements Runnable { private RedisMessageQueue redisMessageQueue; public LoggerWorker(RedisMessageQueue redisMessageQueue) { this.redisMessageQueue = redisMessageQueue; } @Override public void run() { while (! Thread.interrupted()) { String message; if ((message = redisMessageQueue.poll()) != null) { log.info("{} 执行 {}", Thread.currentThread().getName(), message); } else { try { Thread.sleep(500L); } catch (InterruptedException e) { log.error("", e); break; } } } } }
3,调用示例
生产:
@PostMapping("/producer") public void push(String message, long delay) { redisMessageQueue.put(message, delay, TimeUnit.MILLISECONDS); }
消费:
@PostMapping("/consumer") public void newThread() { Thread consumer = new Thread(new LoggerWorker(redisMessageQueue)); consumer.setDaemon(true); consumer.start(); }