Redisson分布式锁的简单使用

一:前言

我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id当做唯一的值!
而uuid是递增生成的,从1开始一直递增,那么在同一台机器上运行代码,加上同步方法(synchronized),这个生成id的方法就是ok!

但是因为业务扩展或者说为了安全,项目运行在两台机器上,此时单个的同步方法(synchronized)就不能防止id的重复了!!!

要解决上面的这个问题,其他有如下解决办法!
(1):每台机器生产Id的代码,key+id 可以在前加上机器编号区分,key + id --- >机器唯一编号 + key + id
(2):使用数据库行锁(单个数据库的是时候),在需要插入id的表加上行锁,防止数据重复导致程序异常!
(3):使用分布式锁

二:分布式锁简介
网上有很多的讲解分布式锁的文章,但是细细分析很多的代码还是有很多的问题的,如下代码片段摘自博文:
https://my.oschina.net/91jason/blog/517996?p=1
http://blog.csdn.net/u010359884/article/details/50310387

public void lock(long timeout) {
        long nano = System.nanoTime();
        timeout *= 1000000;
        final Random r = new Random();
        try {
            while ((System.nanoTime() - nano) < timeout) {
                if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
                    redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
                    locked = true;
                    logger.debug("add RedisLock[" + key + "].");
                    break;
                }
                Thread.sleep(3, r.nextInt(500));
            }
        } catch (Exception e) {
        }
    }
    

博主也说了:如果长时间获取不到,就会获取锁失败,相当于没加锁!
这里还有可能发生其他问题:
(1)并发情况,expire主动释放锁的时候,可能释放的是别人的锁(不懂请查询资料)
(2)Redis服务挂掉,锁失败,相当于没加锁!
注:使用的时候要注意上面问题!!!
还有一种摘自博文:
http://www.cnblogs.com/0201zcr/p/5942748.html
这个博问分析的:

 while (timeout >= 0) {
            long expires = System.currentTimeMillis() + expireMsecs + 1;
            String expiresStr = String.valueOf(expires); //锁到期时间
            if (this.setNX(lockKey, expiresStr)) {
                // lock acquired
                locked = true;
                return true;
            }

            String currentValueStr = this.get(lockKey); //redis里的时间
            if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
                //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的
                // lock is expired

                String oldValueStr = this.getSet(lockKey, expiresStr);
                //获取上一个锁到期时间,并设置现在的锁到期时间,
                //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                    //防止误删(覆盖,因为key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,但是因为什么相差了很少的时间,所以可以接受

                    //[分布式的情况下]:如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁
                    // lock acquired
                    locked = true;
                    return true;
                }
            }
            timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS;

            /*
                延迟100 毫秒,  这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程,
                只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足.
                使用随机的等待时间可以一定程度上保证公平性
             */
            Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);

        }
        

这个相比第一个完善了误删除key的问题,但是要合理的设置超时时间,否则的话,也会使锁失效。

三:Redisson分布式锁的介绍和简单的使用
Redisson的介绍可以到:https://github.com/redisson/redisson/wiki/1.-%E6%A6%82%E8%BF%B0 这里去了解!
我这里说一下使用时候要注意的问题:

1:文档里面说明了支持Redis 2.8以上版本,支持Java1.6+以上版本。根据自己的环境选择合适的版本!

2:2.8.1的redisson 需要使用 netty的jar包, 否则报错:
Hopper: java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup。

3:2.8.1的redisson需要jackson 2.5+版本,否则报错bjectMapper.addMixIn method not fond。

我写了一个简单的例子,自己也做了一下测试,使用的Redis主从+哨兵模式!
demo的目录结构,具体的源码我放到github上面,地址:https://github.com/dufyun/kuyu/tree/master/redissondemo

这里写图片描述

注:这里一定要先安装Redis服务,如果没有安装Redis服务,请参考这篇:http://blog.csdn.net/u010648555/article/details/69944668
如果Redis服务安装到服务器上面,请修改代码中的Redis地址和端口!否则运行不起了!

运行这个类UUidGeneratorLockTest就可以看到效果!测试结果我也在readme.txt进行了总结!

如果在测试和学习的过程中有疑问,可以随时和我联系,也可以加左侧的群互相探讨!谢谢!

四:总结
这个时代,信息爆炸,各种技术博文之间互相复制,真正好的文章还是需要鉴别的!
我也要反思,自己之前也写过一些博文,也是遇到问题了,去网上搜一些解决方案,很多方案确实是理论上可以解决当前遇到的问题,当时去深究,就会发现很多的不完整性!

多思考,多测试!让代码能够更加高效和安全!

欢迎访问我的csdn博客,我们一同成长!

"不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!"

博客首页http://blog.csdn.net/u010648555

转载于:https://www.cnblogs.com/aflyun/p/6697834.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Redisson是一个基于Redis实现的Java驻内存数据网格(In-Memory Data Grid)和分布式锁(Distributed Lock)框架,它提供了一系列的分布式数据结构,其中包括分布式锁的实现。 使用Redisson实现分布式锁非常简单,只需要遵循以下步骤: 1. 引入Redisson的依赖包: ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.12.6</version> </dependency> ``` 2. 创建Redisson客户端对象: ```java Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); ``` 3. 获取锁对象: ```java RLock lock = redisson.getLock("myLock"); ``` 4. 加锁: ```java lock.lock(); ``` 5. 执行业务逻辑: ```java try { // 执行业务逻辑 } finally { // 释放锁 lock.unlock(); } ``` 完整的示例代码如下: ```java public class MyService { private RedissonClient redisson; public MyService() { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); redisson = Redisson.create(config); } public void myMethod() { RLock lock = redisson.getLock("myLock"); try { lock.lock(); // 执行业务逻辑 } finally { lock.unlock(); } } } ``` 需要注意的是,在执行业务逻辑的过程中,一定要放在try...finally块中,并在finally块中释放锁,以确保在出现异常时锁能够正确地被释放。 ### 回答2: Redisson是一种基于Redis实现的分布式锁框架。以下是Redisson分布式锁使用说明: 1. 引入Redisson依赖:首先需要在项目中引入Redisson的依赖,可以通过Maven或者Gradle等构建工具来管理依赖。 2. 创建RedissonClient:使用RedissonClient可以连接到Redis服务器,并获取一个分布式锁对象。 3. 加锁:使用分布式锁对象可以通过lock()方法来获取锁,该方法默认的锁超时时间是30秒,超过该时间锁会自动释放。也可以使用自定义的锁超时时间。 4. 解锁:在加锁的代码块执行完毕后,需要调用unlock()方法手动释放锁,确保锁的释放,避免死锁的产生。 5. 锁的可重入性:Redisson分布式锁支持可重入性,即同一个线程可以多次获取同一个锁,在释放锁的时候需要调用相应次数的unlock()方法来释放锁。 6. 锁的异步执行:Redisson分布式锁也支持异步执行,即lock()方法可以通过异步方式获取锁。 7. 锁的公平性:Redisson分布式锁可以选择是否公平锁,默认为非公平锁,即不保障获取锁的顺序。可以通过配置参数来设置公平锁。 8. 锁监控:Redisson提供了监控分布式锁的功能,可以通过调用getLock("/lock")方法来监控名为"lock"的锁的情况。 总结来说,Redisson分布式锁使用非常简单,只需要引入依赖、创建客户端、加锁和解锁即可。同时,Redisson还提供了可重入性、异步执行、公平锁和锁监控等功能,可以根据实际需求进行配置和使用。通过使用Redisson分布式锁,可以有效地控制多线程环境下共享资源的访问,避免数据不一致和竞态条件的发生。 ### 回答3: Redisson是一个基于Redis的Java实现,提供了一系列分布式相关的功能,其中包括分布式锁使用使用Redisson实现分布式锁,首先需要创建一个RedissonClient实例,通过该实例可以获取一个RLock对象,RLock提供了加锁和释放锁的方法。 在加锁方面,Redisson支持公平锁和非公平锁。公平锁会按照请求的顺序依次加锁,而非公平锁则允许插队,谁先抢到锁就谁先执行。通过调用RLock对象的lock()方法可以获取锁,该方法会一直阻塞直到获取到锁为止。如果不希望一直阻塞,可以使用tryLock()方法,该方法会尝试获取锁一段时间,如果超过指定的等待时间仍未获取到锁,则返回false。 在释放锁方面,可以使用unlock()方法来释放锁,只有加锁方才能释放锁。可以通过判断当前线程是否持有锁,再决定是否释放锁。 使用Redisson分布式锁还有一些其他的特性,比如锁的自动续约、可重入锁、可中断锁等,这些特性都可以通过相应的方法来使用。 总的来说,Redisson分布式锁使用起来非常方便,只需要简单的几行代码就可以实现分布式环境下的锁功能。但需要注意的是,在使用分布式锁时要考虑并发情况、死锁问题以及锁的粒度等,以确保代码的正确性和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值