赞
踩
有锁才有自由,生活中不存在绝对的自由,绝对的自由通常对应的无序和混沌,只有在道德、法律、伦理的约束下的相对自由,才能使人感受到自由。
而在多线程编程中,锁是至关重要的,锁就是道德,就是法律约束,没有锁的多线程环境将会是混乱的,所有线程都在争夺资源,最后的结果就是导致系统崩溃,而有了锁之后,多线程环境才能稳定高效的工作。
某些原因,获取锁失败-------没有在至少N/2+1个Redis实例取到锁,或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁,但是客户端没有得到响应,而导致接下来的一段时间不能被重新获取锁。
redisson已经有对redlock算法封装,只需要拿来小心使用即可。
POM依赖
- <dependency>
- <groupId>org.redisson</groupId>
- <artifactId>redisson</artifactId>
- <version>3.3.2</version>
- </dependency>
redission封装的redlock算法实现的分布式锁用法,非常简单,跟重入锁(ReentrantLock)有点类似,使用的RedLock做分布式锁管理,用spring注解事务管理,具体使用:
- Config config = new Config();
- config.useSentinelServers().addSentinelAddress("127.0.0.1:6369","127.0.0.1:6379", "127.0.0.1:6389")
- .setMasterName("masterName")
- .setPassword("password").setDatabase(0);
- RedissonClient redissonClient = Redisson.create(config);
- // 还可以getFairLock(), getReadWriteLock()
- RLock redLock = redissonClient.getLock("REDLOCK_KEY");
- boolean isLock;
- try {
- isLock = redLock.tryLock();
- // 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。
- isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS);
- if (isLock) {
- //TODO if get lock success, do something;
- }
- } catch (Exception e) {
- } finally {
- // 无论如何, 最后都要解锁
- redLock.unlock();
- }
但是在实现过程中,遇到如下两个映像深刻的问题:
1、分布式锁与spring注解事务共用产生的问题
2、锁在事务提交前超时问题
- public markScenicSpot(){
- //设置锁为destId
- RLock lock = redisson.getLock("Afanti_markScenicSpot_updateCountwantAndCountbeenLock_" + ID);
- //尝试获取锁
- long lockTimeOut = 30; //持有锁超时时间
- boolean success = lock.tryLock(5, lockTimeOut, TimeUnit.SECONDS);
- if (success) {
- try {
- //业务逻辑实现
- }catch (Exception e){
- throw e;
- } finally{
- //释放锁
- lock.unlock();
- }
- } else {
- log.error("获取锁失败!更新失败!");
- throw new BizException(ErrorCodeEnum.PROCESS_DATA_ERROR);
- }
- }
spring注解事务@Transactional和分布式锁一起使用的问题
这是因为@Transactional是通过方法,是否抛出异常?来判断事务是否回滚,还是提交,此时方法已经结束。
但是我们必须在方法结束之后释放锁,因此在释放锁之后,此时事务还没提交,由于锁已经释放,其他进程可以获得锁,并从数据库查询地点标记数,但是此时,前一个进程没有提交数据。
该进程查到的数据,不是最新的数据。
尽管这个过程只要很短的时间(实际测试过程中,这个过程只要几毫秒),但是高并发的情况,还是会出问题。
- public markScenicSpot(){
- RLock lock = redisson.getLock("Afanti_markScenicSpot_updateCountwantAndCountbeenLock_
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。