Redis消息隊(duì)列與訂閱者發(fā)布者

Redis列表List是采用的雙端鏈表的結(jié)構(gòu),所有頭尾存取元素特別快


image.png

手動(dòng)操作一下在java中實(shí)現(xiàn)redis的消息隊(duì)列柠偶,通過生產(chǎn)者和消費(fèi)者的模式進(jìn)行實(shí)現(xiàn)

生產(chǎn)者代碼:

    public class Producer extends Thread{
        public static final String messageKey = "message";
        private JedisPool jedisPool;
        private String producerName;
        private Jedis jedis;
        private volatile int count = 0;
    
        public Producer(String producerName){
            this.producerName = producerName;
            jedisPool = new JedisPool("127.0.0.1",6379);//redis的ip和端口
            jedis = jedisPool.getResource();
        }
    
    
        public void putMessage(String message){
            jedis.lpush(messageKey,message);
            count++;
        }
    
        public void run(){
            while (true){
                try {
                    putMessage(RandomStringUtils.randomAlphabetic(5));//獲取長(zhǎng)度為5的任意字符串
                    TimeUnit.SECONDS.sleep(1);//線程進(jìn)入為時(shí)一秒的休眠狀態(tài)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public int getCount(){
            return count;
        }
    
        public static void main(String[] args) throws InterruptedException {
            Producer producer = new Producer("myTest");
            producer.start();
    
            for (;;){
                System.out.println("生產(chǎn)者:"+producer.producerName+"生產(chǎn)了"+producer.getCount()+"對(duì)象");
                TimeUnit.SECONDS.sleep(10);
            }
        }
    }     

消費(fèi)者代碼

    public class Customer extends Thread{
        private String customerName;
        private volatile int count = 0;
        private Jedis jedis;
        private JedisPool jedisPool;
    
        public Customer(String customerName){
            this.customerName = customerName;
            jedisPool = new JedisPool("127.0.0.1",6379);
            jedis = jedisPool.getResource();
        }
    
        //注意點(diǎn)
        public void getMessage(){
            List<String> result = jedis.blpop(0,Producer.messageKey);
            if (result.size()!=0){
                String rkey = result.get(0);
                if (rkey.equals(Producer.messageKey)){
                    String msg = result.get(1);
                    count++;
                    showMessage(msg);
                }
            }
        }
    
        public void showMessage(String msg){
            System.out.println("消費(fèi)者:"+customerName+"消息內(nèi)容是"+msg+"這是第"+count+"個(gè)產(chǎn)品");
        }
    
        public void run(){
            while (true){
                getMessage();
            }
        }
    
        public static void main(String[] args) {
            Customer customer = new Customer("消費(fèi)一號(hào)");
            customer.start();
        }
    
    }

其中比較重要的方法就是getMessage(),可以看到我使用的是blpop()的方式取出消息的次哈,因?yàn)閎lpop是一個(gè)阻塞的方法胎署,當(dāng)消息隊(duì)列中沒有元素,那么就會(huì)一直進(jìn)入到阻塞的狀態(tài)亿乳,如果使用lpop的方式硝拧,那么就會(huì)一直進(jìn)行嘗試,會(huì)浪費(fèi)很多的資源葛假,得不償失障陶,所以在此使用擁有阻塞功能的blpop()方法可以提供資源的利用率。


redis還提供了訂閱者和發(fā)布者的功能聊训,類似于QQ聊天抱究,可以私聊,群聊的方式带斑。

發(fā)布者代碼

    public class Publisher {
        public static final String channel = "aChannel";
        private JedisPool jedisPool;
        private Jedis jedis;
        private String pname;
    
        public Publisher(String pname){
            this.pname = pname;
            jedisPool = new JedisPool("127.0.0.1",6379);
            jedis = jedisPool.getResource();
        }
    
        public void publish(String msg){
            if (org.apache.commons.lang.StringUtils.isBlank(msg))
                return;
            jedis.publish(channel,msg);
        }
    
        public static void main(String[] args) {
            Publisher publisher = new Publisher("發(fā)布者");
            publisher.publish("cececcee");
        }
    } 

這個(gè)代碼塊主要注意在方法publish中鼓寺,發(fā)布消息的時(shí)候,消息不能為空勋磕,如果傳入空值字符串則直接返回妈候。

訂閱者

    public class Subscriber {
        private final String exitInfo = "exit";
        private JedisPool jedisPool;
        private Jedis jedis;
        private String subscriber;
    
        public Subscriber(String subscriber){
            this.subscriber = subscriber;
            jedisPool = new JedisPool("127.0.0.1",6379);
            jedis = jedisPool.getResource();
        }
    
        public void subscribe(String ...channel){
            if (channel==null || channel.length<=0)
                return;
    
            JedisPubSub jedisPubSub = new JedisPubSub() {
                @Override
                public void onMessage(String channel, String message) {
                    if (Publisher.channel.equals(channel)){
                        System.out.println("接收到頻道:"+channel+"的消息:"+message);
                        if (message.equals(exitInfo)){
                            System.exit(0);
                        }
                    }
                }
    
                @Override
                public void onSubscribe(String channel, int subscribedChannels) {
                    if (Publisher.channel.equals(channel)){
                        System.out.println("訂閱了頻道:"+channel);
                    }
                }
            };
            jedis.subscribe(jedisPubSub,channel);
        }
    
        public static void main(String[] args) {
            Subscriber subscriber = new Subscriber("訂閱者");
            subscriber.subscribe(Publisher.channel);
        }
    }       

訂閱者中,主要注意JedisPubSub這個(gè)類挂滓,JedisPubSub類是一個(gè)沒有抽象方法的抽象類,里面方法都是一些空實(shí)現(xiàn)苦银,所以我們可以選擇性的去重寫某些方法來實(shí)現(xiàn)我們的目的,在代碼塊中可以看出我重寫了onMessage()方法和onSubscribe()方法,前一個(gè)方法是在接收數(shù)據(jù)時(shí)候的處理幔虏,后一個(gè)方法是在訂閱頻道時(shí)候的處理纺念,最后再調(diào)用jedis的subscribe()方法來實(shí)現(xiàn)訂閱頻道。


image.png

image.png

經(jīng)過測(cè)試想括,成功發(fā)送和接收信息陷谱。

總結(jié)

使用Redis的List數(shù)據(jù)結(jié)構(gòu)可以簡(jiǎn)單迅速地做一個(gè)消息隊(duì)列,同時(shí)Redis提供的BRPOP和BLPOP等指令解決了頻繁調(diào)用Jedis的rpop和lpop方法造成的資源浪費(fèi)問題瑟蜈。除此之外烟逊,Redis提供對(duì)發(fā)布/訂閱模式的指令,可以實(shí)現(xiàn)消息傳遞踪栋、進(jìn)程間通信焙格。

補(bǔ)充說明隨機(jī)字符串實(shí)現(xiàn)類

    //產(chǎn)生5位長(zhǎng)度的隨機(jī)字符串,中文環(huán)境下是亂碼
    RandomStringUtils.random(5);

    //使用指定的字符生成5位長(zhǎng)度的隨機(jī)字符串
    RandomStringUtils.random(5, new char[]{'a','b','c','d','e','f', '1', '2', '3'});
    
    //生成指定長(zhǎng)度的字母和數(shù)字的隨機(jī)組合字符串
    RandomStringUtils.randomAlphanumeric(5);

    //生成隨機(jī)數(shù)字字符串
    RandomStringUtils.randomNumeric(5);
    
    //生成隨機(jī)[a-z]字符串夷都,包含大小寫
    RandomStringUtils.randomAlphabetic(5);

    //生成從ASCII 32到126組成的隨機(jī)字符串 
    RandomStringUtils.randomAscii(4)

想要使用這個(gè)類的方法需要導(dǎo)入相應(yīng)的包

    <dependency>
        <groupId>org.apache.directory.studio</groupId>
        <artifactId>org.apache.commons.lang</artifactId>
        <version>2.6</version>
    </dependency>

參考鏈接:https://blog.csdn.net/qq_34212276/article/details/78455004

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市予颤,隨后出現(xiàn)的幾起案子囤官,更是在濱河造成了極大的恐慌,老刑警劉巖蛤虐,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件党饮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡驳庭,警方通過查閱死者的電腦和手機(jī)刑顺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饲常,“玉大人蹲堂,你說我怎么就攤上這事”从伲” “怎么了柒竞?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)播聪。 經(jīng)常有香客問我朽基,道長(zhǎng),這世上最難降的妖魔是什么离陶? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任稼虎,我火速辦了婚禮,結(jié)果婚禮上招刨,老公的妹妹穿的比我還像新娘霎俩。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布茸苇。 她就那樣靜靜地躺著排苍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪学密。 梳的紋絲不亂的頭發(fā)上淘衙,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音腻暮,去河邊找鬼彤守。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哭靖,可吹牛的內(nèi)容都是我干的具垫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼试幽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼筝蚕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铺坞,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤起宽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后济榨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坯沪,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年擒滑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腐晾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丐一,死狀恐怖藻糖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钝诚,我是刑警寧澤颖御,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站凝颇,受9級(jí)特大地震影響潘拱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拧略,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一芦岂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垫蛆,春花似錦禽最、人聲如沸腺怯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呛占。三九已至,卻和暖如春懦趋,著一層夾襖步出監(jiān)牢的瞬間晾虑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工仅叫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帜篇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓诫咱,卻偏偏與公主長(zhǎng)得像笙隙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坎缭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容