package com.jarvis.cache.lock;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
/**
* 基于Redis+Lua实现分布式锁; 实现方法更容易理解,但性能相对会差些
* @author jiayu.qiu
*/
public abstract class AbstractRedisLockWithLua implements ILock {
/**
* 分布式锁 KEY[1] lock key <br>
* ARGV[1] 过期时间 ARGV[2] 缓存时长 返回值: 如果执行成功, 则返回1; 否则返回0
*/
private static final String lockScriptStr="local lockKey= KEYS[1]\n"//
+ "local lock = redis.call('SETNX', lockKey, ARGV[1])\n" // 持锁
+ "if lock == 0 then\n" //
+ " return 0\n" //
+ "end\n" //
+ "redis.call('EXPIRE', lockKey, tonumber(ARGV[2]))\n" // 持锁n秒
+ "return 1\n";
private static byte[] lockScript;
static {
try {
lockScript=lockScriptStr.getBytes("UTF-8");
} catch(Exception e) {
e.printStackTrace();
}
}
protected abstract Long eval(byte[] lockScript, String key, List<byte[]> args) throws UnsupportedEncodingException;
protected abstract void del(String key);
@Override
public boolean tryLock(String key, int lockExpire) {
try {
List<byte[]> args=new ArrayList<byte[]>();
long expire2=System.currentTimeMillis() + (lockExpire * 1000);
args.add(String.valueOf(expire2).getBytes("UTF-8"));
args.add(String.valueOf(lockExpire).getBytes("UTF-8"));
Long rv=eval(lockScript, key, args);
return null != rv && rv.intValue() == 1;
} catch(Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public void unlock(String key) {
try {
del(key);
} catch(Throwable e) {
}
}
}