Redisson解决分布式锁

Redisson

是一个在Redis基础上实现的Java驻内存数据网格,提供了一系列分布式的Java常用对象,还提供了很多分布式服务。提供了使用Redis的最简单和最边界的方法。宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中的放在处理业务逻辑上。

1. Hello Redisson

  • 引入依赖

            <dependency>
                <groupId>org.redissongroupId>
                <artifactId>redissonartifactId>
                <version>3.17.1version>
            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;
        }
    

你可能感兴趣的:(#,并发数据,2022,分布式,redis,java)