public class RedisDistributedLock {
private static final String LOCK_KEY_PREFIX = "lock:";
private static final long LOCK_EXPIRE_TIME = 30000L;
private RedisTemplate<String, Object> redisTemplate;
private String lockKey;
private String lockValue;
private boolean locked = false;
public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, String lockKey, String lockValue) {
this.redisTemplate = redisTemplate;
this.lockKey = LOCK_KEY_PREFIX + lockKey;
this.lockValue = lockValue;
}
public boolean lock() {
if (redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue)) {
redisTemplate.expire(lockKey, LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS);
locked = true;
return true;
} else {
return false;
}
}
public void unlock() {
if (locked) {
redisTemplate.delete(lockKey);
}
}
}
@RestController
public class UserController {
private RedisTemplate<String, Object> redisTemplate;
@Autowired
public UserController(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") String id) throws InterruptedException {
RedisDistributedLock lock = new RedisDistributedLock(redisTemplate, "user:" + id, UUID.randomUUID().toString());
try {
while (!lock.lock()) {
Thread.sleep(100);
}
// 处理业务逻辑
return new User();
} finally {
lock.unlock();
}
}
}
public class RedisDistributedLock {
private static final String LOCK_SCRIPT = "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then redis.call('pexpire', KEYS[1], ARGV[2]) return true else return false end";
private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
private static final String LOCK_KEY_PREFIX = "lock:";
private static final long LOCK_EXPIRE_TIME = 30000L;
private RedisTemplate<String, Object> redisTemplate;
private String lockKey;
private String lockValue;
private boolean locked = false;
private String lockScript;
private String unlockScript;
public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, String lockKey, String lockValue) {
this.redisTemplate = redisTemplate;
this.lockKey = LOCK_KEY_PREFIX + lockKey;
this.lockValue = lockValue;
this.lockScript = new DefaultRedisScript<>(LOCK_SCRIPT, Boolean.class).getScriptAsString();
this.unlockScript = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class).getScriptAsString();
}
public boolean lock() {
Object result = redisTemplate.execute(new DefaultRedisScript<>(lockScript, Boolean.class), Collections.singletonList(lockKey), lockValue, LOCK_EXPIRE_TIME);
locked = (Boolean) result;
return locked;
}
public void unlock() {
if (locked) {
redisTemplate.execute(new DefaultRedisScript<>(unlockScript, Long.class), Collections.singletonList(lockKey), lockValue);
}
}
}
int count = 0;
while (count < retryCount) {
if (lock()) {
return true;
}
count++;
Thread.sleep(retryInterval);
}
return false;
}
public void unlockWithRetry(int retryCount, long retryInterval) throws InterruptedException {
int count = 0;
while (count < retryCount) {
try {
unlock();
break;
} catch (Exception e) {
count++;
Thread.sleep(retryInterval);
}
}
}
public class RedisDistributedLock {
private static final String LOCK_KEY_PREFIX = "lock:";
private static final long LOCK_EXPIRE_TIME = 30000L;
private static final int RETRY_COUNT = 3;
private static final long RETRY_INTERVAL = 100L;
private RedisTemplate<String, Object> redisTemplate;
private String lockKey;
private String lockValue;
private boolean locked = false;
private List<RedisConnection> connections = new ArrayList<>();
public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, String lockKey, String lockValue) {
this.redisTemplate = redisTemplate;
this.lockKey = LOCK_KEY_PREFIX + lockKey;
this.lockValue = lockValue;
}
public boolean lock() {
for (int i = 0; i < RETRY_COUNT; i++) {
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
connections.add(connection);
try {
byte[] keyBytes = redisTemplate.getKeySerializer().serialize(lockKey);
byte[] valueBytes = redisTemplate.getValueSerializer().serialize(lockValue);
long expireTime = System.currentTimeMillis() + LOCK_EXPIRE_TIME + 1;
for (int j = 0; j < connections.size(); j++) {
RedisConnection conn = connections.get(j);
if (j == connections.size() - 1) {
conn.set(keyBytes, valueBytes, Expiration.milliseconds(LOCK_EXPIRE_TIME), RedisStringCommands.SetOption.SET_IF_ABSENT);
} else {
conn.set(keyBytes, valueBytes, Expiration.milliseconds(LOCK_EXPIRE_TIME), RedisStringCommands.SetOption.SET_IF_ABSENT);
conn.pExpire(keyBytes, expireTime);
}
}
locked = true;
return true;
} catch (Exception e) {
// ignore
}
try {
Thread.sleep(RETRY_INTERVAL);
} catch (InterruptedException e) {
// ignore
}
}
return false;
}
public void unlock() {
for (RedisConnection connection : connections) {
try {
connection.del(redisTemplate.getKeySerializer().serialize(lockKey));
} catch (Exception e) {
// ignore
} finally {
connection.close();
}
}
connections.clear();
locked = false;
}
}
免责申明:
本文系转载,版权归原作者所有,如若侵权请联系我们进行删除!
《数据治理行业实践白皮书》下载地址:https://fs80.cn/4w2atu
《数栈V6.0产品白皮书》下载地址:https://fs80.cn/cw0iw1
想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网:https://www.dtstack.com/?src=bbs
同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术群」,交流最新开源技术信息,群号码:30537511,项目地址:https://github.com/DTStack