分布式锁
来源:互联网 发布:钉钉网络异常 编辑:程序博客网 时间:2024/05/22 07:51
在分布式系统中,数据的一致性是个重要的问题,为了实现数据一致性,需要很多技术方案来支持,比如分布式锁等。分布式锁又有多种实现方式,如数据库乐观锁,redis分布式锁,还有zookeeper分布式锁。
这里介绍一下redis分布式锁的实现,直接看代码。
/** * 获取分布式锁 * * @param lockName 竞争获取锁key * @param acquireTimeoutInMS 获取锁超时时间 * @param lockTimeoutInMS 锁的超时时间 * @return 获取锁标识 */public String acquireLockWithTimeout(String lockName, long acquireTimeoutInMS, long lockTimeoutInMS) { logger.info("尝试获取锁,锁名:{}", lockName); String retIdentifier = null; String identifier = UUID.randomUUID().toString(); String lockKey = lockPrefix + lockName; long end = System.currentTimeMillis() + acquireTimeoutInMS; try { BoundValueOperations<String, String> boundValueOperations = stringRedisTemplate.boundValueOps(lockKey); while (System.currentTimeMillis() < end) { boolean success = boundValueOperations.setIfAbsent(identifier); if (success) { //如果获得锁 boundValueOperations.expire(lockTimeoutInMS, TimeUnit.MILLISECONDS); retIdentifier = identifier; return retIdentifier; } //未设置锁的过期时间(可能是设置过期时间时发生异常导致) if (boundValueOperations.getExpire() == -1) { boundValueOperations.expire(lockTimeoutInMS, TimeUnit.MILLISECONDS); } try { Thread.sleep(10); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } } catch (Exception e) { throw new BusinessException(ErrorCodeDefinition.ERROR_REDIS_GET,"获取分布式锁异常"); //在外层捕获到该异常时一般继续做业务处理 } return retIdentifier;}/** * 释放锁 * * @param lockName 竞争获取锁key * @param identifier 释放锁标识 * @return */public boolean releaseLock(String lockName, String identifier) { logger.info("尝试释放锁,锁名:{}", lockName); String lockKey = lockPrefix + lockName; boolean retFlag = true; try { BoundValueOperations<String, String> boundValueOperations = stringRedisTemplate.boundValueOps(lockKey); if (identifier.equals(boundValueOperations.get())) { stringRedisTemplate.delete(lockKey); retFlag = true; } } catch (Exception e) { retFlag = false; } return retFlag;}
在业务执行前后,分别获取分布式锁和释放分布式锁。当无法获取分布锁时,即表明已有其他进程/线程正在处理该业务。只有当锁被释放或者锁过期时才能进行新的业务调用。还有另外一种实现方式:
分布式锁实现方式2
public boolean tryLock(String lockKey) { try{ Long time_stamp = System.currentTimeMillis(); BoundValueOperations<String, Long> boundValueOperations = redisTemplate.boundValueOps(lockKey); boolean flag = boundValueOperations.setIfAbsent(time_stamp); if(flag){//获得锁 redisTemplate.expire(lockKey, DEAD_LOCK_EXPIRED_SECONDS, TimeUnit.SECONDS); return true; }else{ //没有获得锁 //查看锁的时间戳进行死锁检查(可能存在锁一直未释放也没有过期时间的情况) Long val = boundValueOperations.get(); if(val==null){ //如果key读取期间被删(释放锁),直接返回 false; return false; }else if((time_stamp - val) > DEAD_LOCK_REMOVE_SECONDS){ //已经超过时间 //当前锁已过期(可能是设置过期时间时出现异常导致) //设置锁的新时间戳,并返回原时间戳(即锁的原标识)。 Long last_value = boundValueOperations.getAndSet(time_stamp); if(val.equals(last_value) ){ //相等则抢占到锁 //重新设置过期时间 redisTemplate.expire(lockKey, DEAD_LOCK_EXPIRED_SECONDS, TimeUnit.SECONDS); return true; }else{ return false; //时间戳已被其他线程 } }else{ //未超时 return false; } } }catch(Exception e){ LOG.error("获取分布式锁异常:{}",e);//当redis异常时,业务流程正常处理 return true; }}public boolean unlock(String lockKey) { try{ redisTemplate.delete(lockKey); }catch(Exception e){ LOG.error("释放分布式锁异常:{}",e); return false; } return true;}
当然,分布式锁也可以通过aop的方式实现。在需要加锁的地方添加分布式锁注解,然后在业务处理方法之前进行前置通知,执行加锁,在业务处理方法之后后置通知释放锁。
阅读全文
0 0
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 分布式锁
- 文档中形状的巧妙运用---案列一
- Redis在Window服务下的安装
- 注意警告:有时候它对我们排查错误很有帮助!
- 根据字节偏移量读取文件
- android 多媒体之播放网络音乐demo
- 分布式锁
- 指向字符串的指针与字符数组
- 解决给一组Button设置Background导致点击效果错乱问题
- php __CLASS__、get_class()与get_called_class()的区别
- Java装箱与拆箱
- 软件测试与软件质量
- javascript
- 一条ssh命令实现端口转发,实现跨机器直接访问
- oracle中的SGA-共享池