#Redis分布式锁Java代码实现
/**
* redis分布式锁 可重入
* */
public class RedisDistributedLock implements Lock {
private StringRedisTemplate stringRedisTemplate;
private String lockName; //KEYS[1]
private String uuidValue; //ARGV[1]
private long expireTime; //ARGV[2]
public RedisDistributedLock(StringRedisTemplate stringRedisTemplate, String lockName) {
this.stringRedisTemplate = stringRedisTemplate;
this.lockName = lockName;
this.uuidValue = IdUtil.simpleUUID() + ":" + Thread.currentThread().getId();
this.expireTime = 50L;
}
@Override
public void lock() {
tryLock();
}
@Override
public boolean tryLock() {
try {
tryLock(-1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
if (time == -1L){
String script = "if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 1 then " +
"redis.call('hincrby', KEYS[1], ARGV[1], 1) " +
"redis.call('expire', KEYS[1], ARGV[2]) " +
"else " +
" return 0 " +
"end";
while(!stringRedisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(lockName), uuidValue, expireTime)) {
// 暂停60毫秒
try { TimeUnit.MILLISECONDS.sleep(60);} catch (InterruptedException e) { e.printStackTrace();};
}
renewExpire();
return true;
}
return false;
}
// 自动续期 watch dog的思想
private void renewExpire() {
String script = "if redis.call('HEXISTS', KEYS[1], ARGV[1]) == 1 then " +
"return redis.call('expire', KEYS[1], ARGV[2]) " +
"else " +
"return 0 " +
"end";
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (stringRedisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList(lockName), uuidValue, expireTime)){
renewExpire();
}
}
}, (this.expireTime * 1000) / 3);
}
@Override
public void unlock() {
String script = "if redis.call('HEXISTS', KEYS[1], ARGV[1]) == 0 then " +
"return nil " +
"elseif redis.call('HINCRBY', KEYS[1] ,ARGV[1], -1) == 0 then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
Long flag = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(lockName), uuidValue, expireTime);
if (flag == null){
throw new RuntimeException("this lock doesn't not exists!!!!!");
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@NotNull
@Override
public Condition newCondition() {
return null;
}
}