利用redis實現消息隊列之queue模式

可以利用redis存儲數據類型的list類型實現消息發送與消費的一對一模式,使用lpush向list的左端推送數據(發送消息),使用rpop從右端接收數據(消費消息)。由於rpop需要週期性的從list中獲取數據,可以考慮使用brpop代替rpop,brpop是一個阻塞方法,直到獲取到數據。代碼如下

生產者的pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.tansun</groupId>
	<artifactId>ProducerTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>
	</dependencies>

</project>
生產者的主方法
package com.tansun;

import redis.clients.jedis.Jedis;

public class ProducerTest {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		Jedis jedis = new Jedis("192.168.229.128", 6379); 
		// 向鍵爲“test queue”的值的左端推入數據
		jedis.lpush("test queue", "message: hello redis queue");
	}

}

消費者的pom文件與生產者相同

消費者的主方法

package com.tansun;

import java.util.List;

import redis.clients.jedis.Jedis;

public class ConsumerTest {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		Jedis jedis = new Jedis("192.168.229.128", 6379);  
		while(true){
			// 設置超時時間爲0,表示無限期阻塞
			List<String> message = jedis.brpop(0, "test queue");
			System.out.println(message);
		}
	}

}

至此,已經實現了消息隊列的queue模式發送和消費消息。

看一下brpop方法源碼,發現還有一個重載的方法,源碼如下:

public List<String> brpop(final int timeout, final String... keys) {
    return brpop(getArgsAddTimeout(timeout, keys));
  }
public List<String> brpop(String... args) {
    checkIsInMultiOrPipeline();
    client.brpop(args);
    client.setTimeoutInfinite();
    try {
      return client.getMultiBulkReply();
    } finally {
      client.rollbackTimeout();
    }
  }
public void brpop(final String[] args) {
    final byte[][] bargs = new byte[args.length][];
    for (int i = 0; i < bargs.length; i++) {
      bargs[i] = SafeEncoder.encode(args[i]);
    }
    brpop(bargs);
  }

protected Connection sendCommand(final Command cmd, final byte[]... args) {
    try {
      connect();
      Protocol.sendCommand(outputStream, cmd, args);
      pipelinedCommands++;
      return this;
    } catch (JedisConnectionException ex) {
      /*
       * When client send request which formed by invalid protocol, Redis send back error message
       * before close connection. We try to read it to provide reason of failure.
       */
      try {
        String errorMessage = Protocol.readErrorLineIfPossible(inputStream);
        if (errorMessage != null && errorMessage.length() > 0) {
          ex = new JedisConnectionException(errorMessage, ex.getCause());
        }
      } catch (Exception e) {
        /*
         * Catch any IOException or JedisConnectionException occurred from InputStream#read and just
         * ignore. This approach is safe because reading error message is optional and connection
         * will eventually be closed.
         */
      }
      // Any other exceptions related to connection?
      broken = true;
      throw ex;
    }
  }

從源碼中可知這個方法可以從多個key獲取元素,並且先從第一個key中獲取元素,再依次向後獲取,根據這個方法的特點,我們可以實現具有優先級的任務隊列,代碼不再贅述。

如果想了解redis實現消息隊列的發佈訂閱模式,可以參考我的另一篇文章 http://blog.csdn.net/jia_costa/article/details/79033899

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章