the lock operation should be atomic, such as get and set value in Redis
lock should expire
del should be atomic, get and del
evolution
version 1
// judge wether has lock, if none add lock
public void addLock() {
String lockName = "lock";
// question: if many thread enter, and will get lock is nil, so it not thread-safe
String lock = getFromRedis(lockName);
if (lock == null) {
setRedisKey(lockName, "value");
// exec logic business
del(lockName);
return;
} else {
// spin
addLock(); // can modify with Thread sleep
}
}
// solution: makes judgment and locking an atomic operation
version 2: get and set lock in Redis is atomic
public void addLock() {
String lockName = "lock";
// makes judgment and locking an atomic operation
Integer lock = setnx(lockName);
if (lock == null) {
// question: if sever is down or unhandle exception here, others thread will wait for lock forever
// exec logic business
del(lockName);
return;
} else {
// spin
addLock()
}
}
// solurion: add lock expire for lock key in Redis
version 3: add lock expire
public void addLock() {
String lockName = "lock";
// makes judgment and locking an atomic operation
Integer lock = setnx(lockName);
if (lock == null) {
// question: if sever is down here, others thread will wait for lock forever
expire(lockName);
// exec logic business
del(lockName);
return;
} else {
// spin
addLock()
}
}
// solution: make get , set and expire is atomic operation
version 4: make get , set and expire is atomic operation
public void addLock() {
String lockName = "lock";
// makes judgment, locking and expire key an atomic operation
String lock = setnxex(lockName, expireTime);
if (lock == "ok") {
// exec logic business
// question: if logic is time-consuming operation and Redis key is expire, so this thread will delete the lock, which is adding by other thread
del(lockName); // get then del, so they should be atomic
return;
} else {
// spin
addLock()
}
}
// solution: make thread just can delete itself lock, and make get then del an atomic operation
version 5: make thread just can delete itself lock, and make get then del an atomic operation[lua]
public void addLock() {
String threadId = Thread.getCurrentThread().getName();
String lockName = "lock";
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
Integer lock = setnxex(lockName, timeout);
if (lock = "ok") {
// exec logic business
delWithLua(lockName, lockName, threadId);
return;
} else {
// spin
addLock()
}
}
// modify: can implement with AOP
more think about lock
spin: times and timeout
cache: 击穿, 穿透, 雪崩
granularity: different pro should has itself lock[lock name should be relative with pro]
non-distributed lock
the evolution of non-distributed locks[Redis]
evolution
version 1
version 2: get and set lock in Redis is atomic
version 3: add lock expire
more think about lock
use redisson