分布式对象

Redisson库对Redis数据类型以及常用的数据增删改查操作做了封装,这里我们简单介绍一下其中比较常用的内容。

键 RKeys

Redisson库对键的操作都位于RKeys接口中。

RKeys rKeys = client.getKeys();
// 匹配查询Key
Iterable<String> keys = rKeys.getKeysByPattern("stu*");
// 删除Key
rKeys.delete("student");

对象桶 RBucket

Redisson提供了RBucket接口,它可以存储任何可序列化的Java对象,对象会以初始化配置中指定的序列化方式存储到Redis中。

// 获取对象桶
RBucket<Student> bucket = client.getBucket("student");
// 存储数据到桶
bucket.set(student);
bucket.expire(Duration.ofSeconds(3));
// 从桶中获取数据
Student s = bucket.get();
// 删除桶
bucket.delete();

上面代码中,我们存储数据时还指定了一个expire过期时间,该方法接收Duration对象作为参数,我们这里指定了3秒的过期时间。

字典 RMap

RMap是一个分布式的集合,它实现了java.util.concurrent.ConcurrentMapjava.util.Map接口。类似RBucketRMap也能以指定泛型参数的方式存储任何可序列化的Java对象,在Redis中RMap会以Hash类型存储。

// 获取RMap
RMap<String, Student> map = client.getMap("studentMap");
// 存入数据到RMap
map.put("s1", student1);
map.put("s2", student2);
map.expire(Duration.ofSeconds(3));
// 从RMap中获取数据
Student s = map.get("s1");
// 从RMap中删除数据
map.remove("s1");
// 删除RMap
map.delete();

这里注意不要弄错RMapRBucket的使用场景,RMap每一次操作键值对都会访问Redis服务器,如果我们只是存取一个完整的对象,不要用RMap而应该使用RBucket

话题(订阅发布) RTopic

RTopic接口封装了Redis的订阅发布功能。

// 获取RTopic
RTopic topic = client.getTopic("topic");
// 设置RTopic监听
topic.addListener(String.class, (charSequence, s) -> {
    // 收到消息
    System.out.println(s);
});

上面代码我们获取了一个话题,并进行了监听。addListener方法的第二个参数接收MessageListener对象,其回调方法为public void onMessage(String channel, SomeObject message)

// 获取RTopic
RTopic topic = client.getTopic("topic");
// 发布消息
topic.publish("你好");

在另一个线程或分布式实例中,我们获取话题,并发布了一条信息。

原子长整型 RAtomicLong

RAtomicLong是一个支持分布式的原子长整数,采用锁的方式读写存储在Redis中的值。

RAtomicLong atomicLong = client.getAtomicLong("cnt");
// 设置值
atomicLong.set(100);
// 获取值
long value = atomicLong.get();
// 删除值
atomicLong.delete();

长整型累加器 RLongAdder

RLongAdder是一个支持分布式的累加器,如果是累加操作其并发性能比直接使用RAtomicLong强得多。但要注意RLongAdder底层实现和RAtomicLong不同,它并没有在Redis中实际存储数据。如果一个持有累加器的RedissonClient销毁或退出,它累加的值也会失去。

// 获取RLongAdder
RLongAdder longAdder = client.getLongAdder("cnt");
// 累加器增加100
longAdder.add(100);
// 累加器增加1
longAdder.increment();
// 读取累加器当前值
long l = longAdder.sum();

信号灯 RSemaphore

并发编程中信号灯用于控制最大同时并发数,信号灯会在初始化时设置若干“许可”,代码判断请求一定数量的许可成功才能执行,没有成功获取许可则需要阻塞等待或返回错误。Redisson中RSemaphore基于Redis实现了分布式环境下的信号灯。

// 获取信号灯
RSemaphore semaphore = client.getSemaphore("semaphore");
// 设置信号灯许可数为3
semaphore.trySetPermits(3);
try {
    // 获取许可(阻塞式)
    semaphore.acquire();
} catch (InterruptedException e) {
    throw new RuntimeException(e);
} finally {
    // 释放许可
    semaphore.release();
}

非阻塞式获取许可使用semaphore.tryAcquire(),获取许可成功是返回true,反之返回falseacquire()tryAcquire()方法可以传入一个整型参数,表示要获取的许可数量。

限流器 RRateLimiter

Redisson还实现了分布式限流器RRateLimiter。限流器会按照指定的时间间隔发放允许调用一段代码的“许可”,分布式程序会尝试获取“许可”,如果尝试获取“许可”失败,则代表已触发限流,这样就能实现请求频率控制了。限流器和信号灯的主要区别是信号灯用于并发数控制,而限流器用于QPS控制,它们底层的原理是类似的。

// 获取限流器
RRateLimiter rateLimiter = client.getRateLimiter("rateLimiter");
// 设置限流器每5秒产生1个许可
rateLimiter.setRate(RateType.OVERALL, 1, 5, RateIntervalUnit.SECONDS);
// 试图获取许可(阻塞式)
rateLimiter.acquire();

和信号灯类似,限流器非阻塞式获取许可使用rateLimiter.tryAcquire(),获取许可成功是返回true,反之返回false

上面代码中,我们设置了限流器每5秒产生1个许可,获取许可时可以采用阻塞和非阻塞的方式,阻塞方式会在获取到许可前阻塞当前线程;非阻塞方式能够根据当前是否成功获取令牌返回truefalse。此外,限流器的acquire()tryAcquire()方法支持一个长整型参数,表示需要获取的许可数量。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。