实现思路
链接:
https://www.processon.com/view/5ca5a76be4b0cfb73427ee0f#map
代码:
public class RedisLock implements Lock {
private static final String LOCK_KEY = "lock";
private ThreadLocal<String> local = new ThreadLocal<>();
/**
* 阻塞式加锁,不管怎么着,拿不到锁不返回
*/
@Override
public void lock() {
if (tryLock()) {
//加锁成功,没必要阻塞
return;
} else {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock();
}
/**
* 解锁使用lua脚本来实现。
* GET 判断 del 把这三个操作打包给redis去执行,使用Lua脚本去执行。(保证这三步操作的原子性)
*/
@Override
public void unlock() {
String script = FileUtil.readFile(FileUtil.PATH);
Jedis redis = new Jedis("localhost");
List<String> keys = new ArrayList<>();
keys.add(LOCK_KEY);
List<String> args = new ArrayList<>();
args.add(local.get());
redis.eval(script, keys, args);
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
/**
* 非阻塞式加锁
*
* @return
*/
@Override
public boolean tryLock() {
// CountDownLatch
//生成随机字符串
String uuid = UUID.randomUUID().toString();
//想redis里面使用setnx加锁
Jedis redis = new Jedis("localhost");
//NX 表示这个key没有值,则设置key的值为value,XX:表示如果有值,才设置成功 EX:失效期单位为s PX:失效期的单位为ms,100ms
//设置值和设置有效期原子操作
final String ret = redis.set(LOCK_KEY, uuid, "NX", "PX", 100);
if (ret != null && ret.equals("OK")) {
local.set(uuid);
return true;
}
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public Condition newCondition() {
return null;
}
}
解锁lua脚本
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end