记录一次redis分布式锁的坑
redis分布式锁的实现方式是:
lock(){ sync(this){
//无法获取自旋 setnx(key,UUID) setex(60s) return UUID } } unlock(key,value){ sync(this){ if(get(key) == UUID){ del(key) } } }
备注:由于redisTemplate版本问题,没有setnxex的原子操作,而且unlock也有两步操作,为了保证单机原子性,加上了sync对象锁,并且lock和unlock锁同一个对象。
看山去一切都很美,但是运行起来发现问题了:并发量一上来,分布式锁并不会正常解锁,而是每次都要等60s自动过期后才能解锁。。。。
仔细分析了下问题原因:
线程A先进入lock方法,获取sync对象锁,获取到分布式锁,释放sync对象锁
线程A执行业务代码
线程B进入lock方法,获取sync对象锁,但无法获取分布式锁,自旋等待
线程A进入unlock方法,尝试获取sync对象锁,但此时sync对象锁被线程B占用,需要等待线程B释放sync对象锁
这时线程A B有死锁,需要等待其中一个锁自动解锁,就是分布式锁的60s,这就解释了为什么每次都要等60s!!!!
而且这种方法还只能在单机保证线程安全,想要实现一个优秀的分布式锁,还必须要满足分布式原子性!