1本地锁比较常用,比如synchronize或者Lock,都是JDK自带的。它们只能锁定当前进程,只适用于单一架构服务。在分布式多服务实例场景下,必须使用分布式锁。2分布式锁2.1分布式锁原理厕所占用理论可以同时去一个地方“占坑”:如果被占用,则执行逻辑;否则等到锁被释放。你可以旋转“被占坑”,旋转到Redis,DB,所有服务都可以访问的地方。2.2分布式锁进化阶段1//占用分布式锁,去redis占坑booleanlock=redisTemplate.opsForValue().setIfAbsent("lock","111");if(lock){//加锁成功...执行businessMap>dataFromDb=getDataFromDb();redisTemplate.delete(key:"lock");//fH?tireturndataFromDb;}else{//锁失败,重试。synchronized()//休眠100ms重试//自旋returnCatalogJsonFromDbwithRedisLock();}问题场景setnx已经占坑,但是业务代码异常或者执行过程中程序宕机,即删除锁的逻辑没有执行成功,导致死锁解决方法:设置锁自动过期,即使没有删除也会自动删除。第2阶段//1。占用分布式锁,去redis占坑booleanlock=redisTemplate.opsForValue().setIfAbsent("lock","110")if(lock){//锁成功...执行业务//突然断电//2。设置过期时间redisTemplate.expire("lock",timeout:30,TimeUnit.SECONDS);Map>dataFromDb=getDataFromDb();//删除锁redisTemplate.delete(key;"lock");returndataFromDb;}else{//锁失败...重试。synchronized()//sleep100mstoretry//spinmethodreturnCatalogJsonFromDbWithRedisLock();}问题场景setnx已设置,即将设置过期时间,宕机,死锁解决方法:设置过期时间和占位符必须是原子操作.Redis支持使用setNxEx命令阶段三//1。分布式锁占坑Booleanlock=redisTemplate.opsForValue().setIfAbsent("lock","110",300,TimeUnit.SECONDS);if(lock)(//锁定成功,执行业务//2.设置过期时间必须和加锁是原子操作//redisTemplate.expire("lock",з0,TimeUnit.SECONDS);Map>dataFromDb=getDataFromDb();//删除锁redisTemplate.delete(key:"lock")returndataFromDb;else{//加锁失败,重试//休眠100ms重试//自旋returngetCatalogJsonFromDbithRedislock()}Phase4已经拿到锁值了,我有UUID,但是现在过期了!别人拿到锁,设置一个新的值,所以if之后删除别人的锁!!也就是说,删除锁不是原子操作.Map>dataFromDb=getDataFromDb();StringlockValue=redisTemplate.opsForValue().get("lock");if(uuid.equals(lockValue)){//删除自己的锁redisTemplate.delete("lock");}问题场景如果发生判断是当前值。当要删除锁时,锁已经过期,别人成功设置了新值。然后deletion是别人的锁解。删除锁必须保证原子性。使用redis+Lua脚本。第五阶段确保锁定/解锁是一个原子操作Stringscript="ifredis.call('get',KEYS[1])==ARGV[1]thenreturnredis.call('del',KEYS[1])elsereturn0end";保证加锁[占用+过期时间]和删除锁[判断+删除]的原子性。比较难的是锁的自动更新。综上所述,比较麻烦的就是锁的自动续订。所以不管是大厂还是中小型公司,我们直接选择Redisson,就解决了这些问题!我们不重复造轮子,但是我们也需要知道这个框架解决的是什么问题,这样我们遇到问题的时候才能快速排查和定位。.本文转载自微信公众号「JavaEdge」,可通过以下二维码关注。转载本文请联系JavaEdge公众号。