public class RedisLock {
private static final String LOCK_PREFIX = "LOCK_";
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final long DEFAULT_SLEEP_TIME = 2000L;
private static final Long RELEASE_SUCCESS = 1L;
@Resource
private JedisConnectionFactory jedisConnectionFactory;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean tryLock(String key, String uuid, long expireTime, TimeUnit timeUnit) {
String result = redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
Jedis jedis = (Jedis) connection.getNativeConnection();
String result = jedis.set(LOCK_PREFIX + key, uuid, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, timeUnit.toMillis(expireTime));
connection.close();
return result;
}
});
return LOCK_SUCCESS.equals(result);
}
/**
* 阻塞
*
* @param key
* @param uuid
* @param expireTime
* @param timeUnit
* @throws InterruptedException
*/
public void lock(String key, String uuid, long expireTime, TimeUnit timeUnit) throws InterruptedException {
while (true) {
boolean lockSuccess = this.tryLock(key, uuid, expireTime, timeUnit);
if (lockSuccess) {
return;
}
//防止一直消耗 CPU
Thread.sleep(DEFAULT_SLEEP_TIME);
}
}
//自定义阻塞时间
public boolean lock(String key, String uuid, long expireTime, TimeUnit timeUnit, long blockTime) throws InterruptedException {
while (blockTime >= 0) {
boolean lockSuccess = this.tryLock(key, uuid, expireTime, timeUnit);
if (lockSuccess) {
return true;
}
blockTime -= DEFAULT_SLEEP_TIME;
Thread.sleep(DEFAULT_SLEEP_TIME);
}
return false;
}
public boolean unlock(String key, String uuid) {
//lua script
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = redisTemplate.execute(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
Jedis jedis = (Jedis) connection.getNativeConnection();
Object result = jedis.eval(script, Collections.singletonList(LOCK_PREFIX + key), Collections.singletonList(uuid));
connection.close();
return result;
}
});
return RELEASE_SUCCESS.equals(result);
}
}