Redisson setNx
1.原子性:key,过期时间保证原子性,中间服务器挂了,无法释放锁(即死锁)
2.解铃还须系铃人,谁加锁,谁解锁,(锁过期,其他程序进入)
过期时间10s,业务耗时15s,A程序加锁,剩余5s内,B程序进入,释放了A程序锁。
思路:加锁时,生成一个随机数value,解锁时判断value是否与加锁时value是否一致,是,才解锁。
应用场景:定时任务
3.看门狗,watch dog,续期(锁过期,其他程序进入,同2,另外一个问题)
过期时间30s,每隔10s续更新时间为30,比如业务执行需要100s,程序执行了,10s,更新过期时间为30s
public void run() {
String uniqueVal = UUID.randomUUID().toString();
String lockKey = RedisKeyHelper.syncFundAvgReturnLockKey();
try {
if (redisMgr.tryLock(lockKey, uniqueVal, LOCK_EXPIRE_TIME_SEC)) {
log.info("Get locked, so to sync avg ret");
process();
}
} catch (Exception e) {
log.error("Fetch fund returns exception", e);
} finally {
redisMgr.releaseLock(lockKey, uniqueVal);
}
}
public boolean tryLock(final String lockKey, final String randomUnValue, final int expireTime) {
List<RedisClient> clients = this.getAliveClients(lockKey);
return this.isAtLeastOneAvailable(clients) ? (Boolean)this.execute(new AbstractRedisCallback<Boolean>() {
public Boolean doOperation(RedisClient client) throws Exception {
return client.tryLock(lockKey, randomUnValue, expireTime);
}
public String getOptionType() {
return "tryLock";
}
}, clients, lockKey, false) : false;
}
public boolean tryLock(String lockKey, String randomUnValue, int expireTime) {
Jedis jedis = null;
try {
jedis = this.jedisPool.getResource();
Long result = (Long)jedis.eval(LuaSecript.SETNX_AND_EXPIRE.getScript(), 1, new String[]{lockKey, randomUnValue, String.valueOf(expireTime)});
if (result == 1L) {
boolean var6 = true;
return var6;
}
} catch (Exception var10) {
this.logger.error("Try lock failed", var10);
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}
lua脚本:
public enum LuaSecript {
SETNX_AND_EXPIRE("local is_existed = redis.call('setnx', KEYS[1], ARGV[1]);if (is_existed == 1) then redis.call('expire', KEYS[1], ARGV[2]);return 1; end; return 0;"),
DEL_KEY_AND_EQUAL_VAL("if (redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]);else return 0;end; "),
ZRANGEBYSCORE_ZREM("local data = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[2], 'WITHSCORES', 'LIMIT', ARGV[3], ARGV[4]);if table.getn(data) > 0 then for k,v in pairs(data) do if (k % 2) ~=0 then redis.call('ZREM', KEYS[1], v);end;end;return data;end;");
private String script;
private LuaSecript(String script) {
this.script = script;
}
public String getScript() {
return this.script;
}
}
if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end