基于Redis的单线程特性和Lua脚本,咱们能够简单的实现一把分布式锁。通常锁在Redis上就是一个KV值,加锁就是新建一个KV,释放锁就把这个KV删除。利用Redis在设置KV时能够设置NX和PX特性,咱们就能够很方便的加锁。废话很少说,先上伪代码:git
String kId = UuidUtil.uuid(); String result = jedis.set("lockName", kId, "NX", "PX", 30 * 1000);
在获取锁时,先在本地生成uuid,做为锁的钥匙。而后用这个uuid做为值去redis设置KV,同时指定NX模式,NX模式的意思就是若是不存在才新增这个KV,若是对应的K已经存在,则放弃新增。这里返回的result=OK表示新增成功即加锁成功,否者加锁失败。后面两个参数PX表明,这个KV有一个过时时间,若是时间过时了,KV会被自动的删除。这个就是解决了上面说到的,若是一个节点没有即时返回锁,那么防止死锁的出现,这里有个锁持有的超时时间。redis
释放锁很简单,就是直接删除这个KV。可是咱们要作到的是,谁获取锁谁才有资格释放,因此在释放时,不能简单的根据K来删除,还须要匹配V的值,这样才能保证谁拿的锁,谁有资格释放。如此一来,释放锁就须要两个步骤。第一步:先获取当前锁对应的值,和本身手上的钥匙是否匹配。第二步,在匹配符合时再操做删除。因此这里就要用Lua脚原本保证这两个步骤的原子性。伪代码以下:网络
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; redis.eval(script, Collections.singletonList("lockName"), Collections.singletonList(kId));
简单说明一下,这里在本地编写一段Lua脚本,大体意思你应该也能够看出来了,先get取到锁对应的值,判断持有的kId是否相等,若是相等才进行del操做,进行锁的删除释放。redis能够原子的让这个脚本执行。分布式
刚才说的所有代码实现,在这个开源项目里面有,里面还有一些别的分布式组件,若是对你有帮助,请给我个star哈。 https://gitee.com/xuan698400/distributed-toolui