原文链接
分布式锁一般有如下的特点:
- 互斥性: 同一时刻只能有一个线程持有锁
- 可重入性: 同一节点上的同一个线程如果获取了锁之后能够再次获取锁
- 锁超时:和J.U.C中的锁一样支持锁超时,防止死锁
- 高性能和高可用: 加锁和解锁需要高效,同时也需要保证高可用,防止分布式锁失效
- 具备阻塞和非阻塞性:能够及时从阻塞状态中被唤醒
lua脚本的方式,放在一个事务中去
1 2 3 4 5 6 7 8 9 10 11 12
| public boolean tryLock_with_lua(String key, String UniqueId, int seconds) { String lua_scripts = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" + "redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end"; List<String> keys = new ArrayList<>(); List<String> values = new ArrayList<>(); keys.add(key); values.add(UniqueId); values.add(String.valueOf(seconds)); Object result = jedis.eval(lua_scripts, keys, values); return result.equals(1L); }
|
1 2 3 4 5 6
| SET key value[EX seconds][PX milliseconds][NX|XX]
EX seconds: 设定过期时间,单位为秒 PX milliseconds: 设定过期时间,单位为毫秒 NX: 仅当key不存在时设置值 XX: 仅当key存在时设置值
|
释放锁的情况,需要对value进行验证,仅释放自己设置的锁?
针对redis集群的方式,采用投票的机制来决定是否真正算获得了锁,也就是所谓的redLock算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
int failedLocksLimit = failedLocksLimit(); List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext(); ) { RLock lock = iterator.next(); boolean lockAcquired; try {
lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS); } catch (RedisConnectionClosedException | RedisResponseTimeoutException e) {
unlockInner(Arrays.asList(lock)); lockAcquired = false; } catch (Exception e) {
lockAcquired = false; } if (lockAcquired) {
acquiredLocks.add(lock); } else {
if (locks.size() - acquiredLocks.size() == failedLocksLimit()) { break; } } } return true; }
|