一、用list实现队列
rpush和lpop右进左出,lpush和rpop左进右出实现FIFO单向队列。
1 public class QueueTest<T> extends AbstractQueue { 2 3 private String qName; 4 5 public QueueTest(String qName){ 6 this.qName = qName; 7 } 8 9 @Override 10 public Iterator iterator() { 11 throw new UnsupportedOperationException(); 12 } 13 14 @Override 15 public int size() { 16 return RedisUtils.llen(qName).intValue(); 17 } 18 19 @Override 20 public boolean offer(Object t) { 21 //String value = JSON.toJSONString(t); 22 return RedisUtils.rpush(qName,t.toString()) == 1; 23 } 24 25 @Override 26 public String poll() { 27 return RedisUtils.lpop(qName); 28 } 29 30 @Override 31 public String peek() { 32 return RedisUtils.lindex(qName,0L); 33 } 34 35 public static void main(String[] args){ 36 QueueTest queue = new QueueTest("queue"); 37 queue.offer(1); 38 queue.offer(2); 39 queue.offer(3); 40 System.out.println("size : " + queue.size()); 41 System.out.println("peek : " + queue.peek()); 42 System.out.println(queue.poll()); 43 System.out.println(queue.poll()); 44 System.out.println(queue.poll()); 45 System.out.println(queue.poll()); 46 RedisUtils.close(); 47 } 48 }
二、用zset实现延迟队列
1 public class DelayQueueTest<E extends Delayed> extends AbstractQueue { 2 3 private String qName; 4 public DelayQueueTest(String qName){ 5 this.qName = qName; 6 } 7 8 @Override 9 public Iterator iterator() { 10 throw new UnsupportedOperationException(); 11 } 12 13 @Override 14 public int size() { 15 return RedisUtils.zcard(qName).intValue(); 16 } 17 18 @Override 19 public boolean offer(Object o) { 20 //延时5s 21 return RedisUtils.zadd(qName,System.currentTimeMillis() + 5000,o.toString()) == 0; 22 } 23 24 @Override 25 public String poll() { 26 Set<String> values = RedisUtils.zrangeByscore(qName,0, System.currentTimeMillis(),0,1); 27 if(values != null && !values.isEmpty()){ 28 String value = values.iterator().next(); 29 if(RedisUtils.zrem(qName,value) > 0){ 30 return value; 31 } 32 } 33 return null; 34 } 35 36 @Override 37 public String peek() { 38 Set<String> values = RedisUtils.zrange(qName,0L,0L); 39 if (values != null && !values.isEmpty()){ 40 String value = values.iterator().next(); 41 return value; 42 } 43 return null; 44 } 45 46 public static void main(String[] args) throws InterruptedException{ 47 DelayQueueTest delayQueue = new DelayQueueTest("delayQueue"); 48 Thread thread = new Thread(new Runnable() { 49 @Override 50 public void run() { 51 for (int i = 0; i < 10; i++) { 52 delayQueue.offer(i); 53 try { 54 Thread.sleep(1000); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 } 59 } 60 }); 61 thread.start(); 62 Thread.sleep(10000); 63 thread.join(); 64 for (;;){ 65 if(delayQueue.peek() == null){ 66 break; 67 } 68 String value = delayQueue.poll(); 69 if(value != null){ 70 System.out.println(value); 71 } 72 Thread.sleep(2000); 73 } 74 RedisUtils.close(); 75 } 76 }
①、延迟队列空了,会无限peek 、poll重试,空轮询不但拉高了服务器的CPU消耗,Redis的QPS也会被拉高,可以让线程sleep一会儿
②、阻塞读,用brpop/blpop代替rpop/lpop,队列没有数据时,会立即进入休眠状态,一旦数据来了,立即醒过来。但空闲连接会自动断开,一直阻塞,闲置过久,会主动断开连接,此时brpop/blpop会抛出异常