1、JDK提供的DelayQueue
一種支持延時獲取元素的無界阻塞隊(duì)列。
內(nèi)部持有一個PriorityQueue,每個對象都被放入了這個隊(duì)列,隊(duì)列中的對象按照優(yōu)先級進(jìn)行了排序,隊(duì)列頭部是最先會超時的對象。
take方法會一直阻塞,直到隊(duì)列頭部的對象超時后才可以被取出。
2、Redis sorted set(ZSET)
實(shí)現(xiàn)思路大同小異。以過期時間的時間戳作為score。
生產(chǎn)者將消息內(nèi)容作為member,時間戳作為score調(diào)用ZADD來生產(chǎn)消息;
消費(fèi)者用ZRANGEBYSCORE命令獲取N秒之前的數(shù)據(jù)進(jìn)行輪詢處理,使用min和max向前推N秒來卡延時的消息。
3、RabbitMQ
rabbitMQ中可以對Message設(shè)置 x-message-ttl(TTL = Time To Live)來控制消息的生存時間。超時以后消息變?yōu)閐ead letter(死信)。
同時,RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可選)兩個參數(shù),如果隊(duì)列內(nèi)出現(xiàn)了dead letter,則按照這兩個參數(shù)重新路由轉(zhuǎn)發(fā)到指定的隊(duì)列。
利用這樣的特性,設(shè)置兩個隊(duì)列,A隊(duì)列無消費(fèi)者,生產(chǎn)者向該隊(duì)列發(fā)送消息,消息設(shè)定TTL;同時設(shè)定A中出現(xiàn)死信以后將消息轉(zhuǎn)發(fā)到B隊(duì)列;B隊(duì)列使用正常設(shè)定即可,所有消費(fèi)者從B讀取消息。
即可完成延時時間為TTL的延時隊(duì)列。
4、Redis 過期回調(diào)
在Redis中開啟監(jiān)聽key是否過期的事件,一旦key過期會觸發(fā)一個callback事件。
有點(diǎn)類似MQ的隊(duì)列事件監(jiān)聽。
5、Kafka
Kafka有專門用于實(shí)現(xiàn)延遲功能的定時器(SystemTimer)。底層使用的是時間輪(TimingWheel)模型(環(huán)形隊(duì)列,下面掛接雙向鏈表)。
操作效率非常高。JDK的DelayQueue插入和刪除操作的平均時間復(fù)雜度為O(nlog(n)),而Kafka基于時間輪可以將插入和刪除操作的時間復(fù)雜度都降為O(1)。