前言
前面介绍Redisson锁的时候,忽略了一个细节,就是在lua脚本中,获取锁的时候,返回的nil,而在lua语义中,nil应该是false或者空,为什么不返回true呢?
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
// 客户端线程成功获取锁,lua脚本返回nil。
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
LUA数值分析
www.runoob.com/lua/lua-dat…
来看看boolean的语义说明:
boolean类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true:
测试脚本
print(type(true))
print(type(false))
print(type(nil))
function isTrueOrFalse(value)
if value then
print("数值:",value,"是 true")
else
print("数值:",value,"是 false")
end
end
print(isTrueOrFalse(0))
print(isTrueOrFalse(-1))
print(isTrueOrFalse(1))
print(isTrueOrFalse(2))
print(isTrueOrFalse(nil))
print(isTrueOrFalse(true))
print(isTrueOrFalse(false))
print(isTrueOrFalse(""))
输出:---------------------
boolean
boolean
nil
数值: 0 是 true
数值: -1 是 true
数值: 1 是 true
数值: 2 是 true
数值: nil 是 false
数值: true 是 true
数值: false 是 false
数值: 是 true
Redisson指令集
RedisCommands接口中定义了一系列的脚本指令,其中就有前面提到的EVAL_NULL_BOOLEAN,EVAL_LONG
RedisStrictCommand<Boolean> EVAL_NULL_BOOLEAN = new RedisStrictCommand<Boolean>("EVAL", new BooleanNullReplayConvertor());
RedisStrictCommand<Long> EVAL_LONG = new RedisStrictCommand<Long>("EVAL");
EVAL_NULL_BOOLEAN
可以看到EVAL_LONG指令没有指定转换器,而EVAL_NULL_BOOLEAN对应的转换器为BooleanNullReplayConvertor,源码如下:
/**
*
* @author Nikita Koksharov
*
*/
public class BooleanNullReplayConvertor implements Convertor<Boolean> {
@Override
public Boolean convert(Object obj) {
return obj == null;
}
}
从转化程序来看,只有脚本返回null时【nil】,方法才能返回true。
EVAL_BOOLEAN
再看看EVAL_BOOLEAN,对应的转换器为BooleanReplayConvertor
public class BooleanReplayConvertor implements Convertor<Boolean> {
@Override
public Boolean convert(Object obj) {
if (obj == null) {
return null;
}
return Long.valueOf(1).equals(obj) || "OK".equals(obj);
}
}
也就是说,我们指定脚本的RedisStrictCommand为EVAL_BOOLEAN时,当方法需要返回true时,脚本里要返回1或者OK才可以。