RedisLock
package com.lybaby.lock;
import cn.hutool.core.lang.Assert;
import com.google.common.base.Function;
import com.lybaby.lock.JedisTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import java.util.Collections;
public class RedisLock {
private static Logger logger = LoggerFactory.getLogger(RedisLock.class);
private static final String LOCK_MSG = "OK";
private static final Long UNLOCK_MSG = 1L;
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private String lockPrefix;
/**
* 循环等待 每次 睡眠时间
*/
private int sleepMillis;
/**
* 锁持有的时间
*/
private int lockHoldMillis;
private JedisTemplate jedisTemplate;
private RedisScript redisScript;
private RedisLock(Builder builder) {
this.jedisTemplate = builder.jedisTemplate;
this.lockPrefix = builder.lockPrefix;
this.sleepMillis = builder.sleepMillis;
this.redisScript = builder.redisScript;
this.lockHoldMillis = builder.lockHoldMillis;
}
/**
* blocking lock
*
* @param key
* @param request
*/
public void lock(String key, String request) throws InterruptedException {
//get connection
String result;
for (; ; ) {
result = set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, lockHoldMillis);
if (LOCK_MSG.equals(result)) {
break;
}
Thread.sleep(sleepMillis);
}
}
/**
* Non-blocking lock
*
* @param key lock business type
* @param request value
* @return true lock success
* false lock fail
*/
public boolean tryLock(final String key, final String request) {
String result = set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, lockHoldMillis);
if (LOCK_MSG.equals(result)) {
return true;
} else {
return false;
}
}
/**
* blocking lock,custom time
*
* @param key
* @param request
* @param timeoutMs 等待获取锁超时时间 (毫秒)
* @return
* @throws InterruptedException
*/
public boolean tryLock(String key, String request, int timeoutMs) throws InterruptedException {
String result;
for (; ; ) {
result = set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, lockHoldMillis);
if (LOCK_MSG.equals(result)) {
return true;
}
timeoutMs -= sleepMillis;
if (timeoutMs < 0) {
return false;
}
Thread.sleep(sleepMillis);
}
}
/**
* Non-blocking lock
*
* @param key lock business type
* @param lockHoldMillis 持有锁的时间(设置redis key 的过期时间)
* @param request value
* @return true lock success
* false lock fail
*/
public boolean tryLock(String key, int lockHoldMillis, String request) {
//get connection
String result;
result = set(lockPrefix + key, request, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, lockHoldMillis);
if (LOCK_MSG.equals(result)) {
return true;
} else {
return false;
}
}
/**
* unlock
*
* @param key
* @param request request must be the same as lock request
* @return
*/
public boolean unlock(String key, String request) {
//lua script
Object result = null;
result = redisScript.eval("lock.lua", Collections.singletonList(lockPrefix + key), Collections.singletonList(request));
if (UNLOCK_MSG.equals(result)) {
return true;
} else {
return false;
}
}
/**
* jedis 方法
*
* @param key
* @param value
* @param nxxx
* @param expx
* @param time
* @return
*/
private String set(final String key, final String value, final String nxxx, final String expx,
final int time) {
return jedisTemplate.execute(new Function<Jedis, String>() {
@Override
public String apply(Jedis jedis) {
return jedis.set(key, value, nxxx, expx, time);
}
});
}
public static class Builder {
private static final String DEFAULT_LOCK_PREFIX = "lock_";
/**
* default sleep time 100 毫秒
*/
private static final int DEFAULT_SLEEP_MILLIS = 100;
private JedisTemplate jedisTemplate;
private RedisScript redisScript;
private String lockPrefix = DEFAULT_LOCK_PREFIX;
private int sleepMillis = DEFAULT_SLEEP_MILLIS;
private int lockHoldMillis = 60 * 1000;
public Builder(JedisTemplate jedisTemplate, RedisScript redisScript) {
this.jedisTemplate = jedisTemplate;
this.redisScript = redisScript;
}
public Builder lockPrefix(String lockPrefix) {
this.lockPrefix = lockPrefix;
return this;
}
public Builder sleepMillis(int sleepMillis) {
this.sleepMillis = sleepMillis;
return this;
}
public Builder lockHoldMillis(int lockHoldMillis) {
this.lockHoldMillis = lockHoldMillis;
return this;
}
public RedisLock build() {
Assert.notNull(this.jedisTemplate);
Assert.notNull(this.redisScript);
return new RedisLock(this);
}
}
public static void main(String[] args) {
//需要初始化
JedisTemplate jedisTemplate = null;
RedisScript redisScript = null;
RedisLock redisLock = new RedisLock.Builder(jedisTemplate, redisScript)
.lockPrefix("disLock_")
.sleepMillis(100)
.build();
}
}
lock.lua
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end