Redisson
是一个在Redis基础上实现的Java驻内存数据网格,提供了一系列分布式的Java常用对象,还提供了很多分布式服务。提供了使用Redis的最简单和最边界的方法。宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中的放在处理业务逻辑上。
1. Hello Redisson
-
引入依赖
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.17.1</version> </dependency>
-
新增配置类
@Configuration public class RedissonConf { @Bean public RedissonClient redissonClient(){ Config config = new Config(); config.useSingleServer().setAddress("redis://localhost:6379"); // 这里默认也是localhost:6379 return Redisson.create(config); } }
-
使用Redisson加锁
@Resource private RedissonClient redissonClient; @Override public String deStock() { // 加锁 RLock lock = redissonClient.getLock("lock"); try { lock.lock(); // lock.lock(10, TimeUnit.SECONDS); // 设置超时时间自动释放锁,可以不手动释放 String stock = stringRedisTemplate.opsForValue().get("stock").toString(); if (Objects.nonNull(stock) && stock.length() != 0){ int stock_num = Integer.parseInt(stock); if (stock_num > 0){ stringRedisTemplate.opsForValue().set("stock", String.valueOf(--stock_num)); } } }finally { lock.unlock(); } return null; }
-
源码分析:其实Redisson的可重入锁也是实现JUC的
Lock
接口,使用lua脚本来对redis操作,也有自动续期的功能,详可以看上篇博客(实现方式类似)。
2. 配置详情
@Configuration
public class RedissonConf {
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.useSingleServer() // 单机redis
.setAddress("redis://localhost:6379"); // 这里默认也是localhost:6379
// .setDatabase(0) // 设置数据库编号
// .setUsername() // 设置用户名
// .setPassword() // 设置密码
// .setConnectionMinimumIdleSize() // 设置连接池最小空闲连接数
// .setConnectionPoolSize() // 设置连接池最大线程数
// .setIdleConnectionTimeout() // 设置线程超时时间,单位:毫秒
// .setConnectTimeout() // 设置获取redis链接超时时间
// .setTimeout() // 设置响应超时时间
return Redisson.create(config);
}
}
3. 公平锁
其公平锁也是实现了JUC下的
Lock
接口。即在多个客户端线程同时请求加锁时,会优先分配给先发出请求的线程。所有的请求都会在一个队列中排队。当某个线程宕机时,Redisson会等待五秒后继续下一个线程。
- 公平锁方法:
@Override public String deStock() { // 加锁 RLock lock = redissonClient.getFairLock("lock"); try { lock.lock(); // lock.lock(10, TimeUnit.SECONDS); // 设置超时时间自动释放锁,可以不手动释放 String stock = stringRedisTemplate.opsForValue().get("stock").toString(); if (Objects.nonNull(stock) && stock.length() != 0){ int stock_num = Integer.parseInt(stock); if (stock_num > 0){ stringRedisTemplate.opsForValue().set("stock", String.valueOf(--stock_num)); } } }finally { lock.unlock(); } return null; }
4. 联锁
将多个
RLock
对象,也就是锁对象,关联为一个联锁,RLock
对象可以来自不同的Redisson实例。
- 特点:必须所有的都加锁成功,才算成功。这种其实就很鸡肋了,只要有一个reids宕机这个锁就失效了。
- 代码实现:
public String deStock() { RLock lock = redissonClient.getLock("lock"); RLock lock2 = redissonClient.getLock("lock"); // 加联锁 RedissonMultiLock multiLock = new RedissonMultiLock(lock2, lock); try { String stock = stringRedisTemplate.opsForValue().get("stock").toString(); if (Objects.nonNull(stock) && stock.length() != 0){ int stock_num = Integer.parseInt(stock); if (stock_num > 0){ stringRedisTemplate.opsForValue().set("stock", String.valueOf(--stock_num)); } } }finally { multiLock.unlock(); } return null; }
5. 红锁
红锁算法,详见上一篇博客。加锁成功与否取决与红锁算法。
-
代码实现:
@Override public String deStock() { RLock lock = redissonClient.getLock("lock"); RLock lock2 = redissonClient.getLock("lock"); // 加红锁 RedissonRedLock redLock = new RedissonRedLock(lock2, lock); try { String stock = stringRedisTemplate.opsForValue().get("stock").toString(); if (Objects.nonNull(stock) && stock.length() != 0){ int stock_num = Integer.parseInt(stock); if (stock_num > 0){ stringRedisTemplate.opsForValue().set("stock", String.valueOf(--stock_num)); } } }finally { redLock.unlock(); } return null; }
6. 读写锁
实现了JUC的
ReadWriteLock
接口,允许有一个写锁和多个读锁。
只有读和读是可以并发的,其余都不可以并发。
- 代码实现(这里没有真正的实现,只有单纯的API调用):
@Override public String deStock() { RReadWriteLock lock = redissonClient.getReadWriteLock("lock"); // 加读锁 lock.readLock().lock(); // 加写锁 lock.writeLock().lock(); try { String stock = stringRedisTemplate.opsForValue().get("stock").toString(); if (Objects.nonNull(stock) && stock.length() != 0){ int stock_num = Integer.parseInt(stock); if (stock_num > 0){ stringRedisTemplate.opsForValue().set("stock", String.valueOf(--stock_num)); } } }finally { // 释放读锁 lock.readLock().unlock(); // 释放写锁 lock.writeLock().unlock(); } return null; }