简介
接上文,redisson也有RingBuffer的实现,采用list的结构来实现,RRingBuffer继承自RQueue接口。使用RRingBuffer的开发人员还可以访问基于队列的方法,例如add(),peek(),poll()和remove(),以及基于集合的方法,例如contains()和isEmpty()。
主要方法
- trySetCapacity,设置环形缓冲区大小,只能设置一次,原因在后面说明;
- capacity,获取buffer设置的容量;
- remainingCapacity,buffer剩余的容量;
如何控制容量
在设置容量的时候,采用了SETNX的设值方式,也就是不能修改。 【NX : 只在键不存在时, 才对键进行设置操作。】
接下来看看写入操作
public RFuture<Boolean> addAsync(V e) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local limit = redis.call('get', KEYS[2]); "
+ "assert(limit ~= false, 'RingBuffer capacity is not defined'); "
+ "local size = redis.call('rpush', KEYS[1], ARGV[1]); "
+ "if size > tonumber(limit) then "
+ "redis.call('lpop', KEYS[1]); "
+ "end; "
+ "return 1; ",
Arrays.asList(getName(), settingsName), encode(e));
}
在方法中我们可以看到,我们新建了一个RRingBuffer,而不对其设定容量,是不能进行添加操作的,返回【RingBuffer capacity is not defined】。写入元素之后,如果列表的size大于我们设定的容量,将最早的一个元素删除。【右边写入,左边删除】这样就保证了不会有超出容量设置的情况发生。
测试用例
@Test
public void testRedisRing() {
RedissonClient redissonClient = create();
RRingBuffer<Object> ring = redissonClient.getRingBuffer("ring");
ring.trySetCapacity(3);
log.info("RING,capacity:{}", ring.capacity());
ring.offer("a");
ring.offer("b");
ring.offer("c");
ring.offer("d");
ring.offer("e");
List<Object> objects = ring.poll(1);
log.info("RING,data:{}", Arrays.toString(objects.toArray()));
log.info("RING,剩余空位:{}", ring.remainingCapacity());
}
输出:
17:45:29.264 [main] INFO com.essay.RingBufferTest - RING,capacity:3
17:45:29.330 [main] INFO com.essay.RingBufferTest - RING,data:[c]
17:45:29.331 [main] INFO com.essay.RingBufferTest - RING,剩余空位:1
说明:我们新建了一个RRingBuffer,指定容量为3,5个元素写入完成之后,redis中最终保存的数据为【c,d,e】。因为在添加元素的过程中,a和b被删除了,这样我们取出的第一个元素就变成了c。