Redis实现的分布式锁,适用于对公共资源争抢更新加锁和解锁
@Slf4j
@Component("redisDistributedLock")
public class RedisDistributedLock {
@Autowired
private JedisClient jedisClient;
public static final String BEAN_NAME = "redisDistributedLock";
private static final int DEFAULT_ACQUIRE_MSECS = 100;
/**
* 锁等待时间,防止线程饥饿
*/
private static final int TIMEOUT_MSECS = 5 * 1000;
/**
* Redis key
*/
private String lockKey = "key_distributed_lock";
/**
* 过期时间,毫秒
*/
private int expiredMsecs = 60 * 1000;
private volatile boolean locked = false;
/**
* 上锁
*
* @return
* @throws InterruptedException
*/
public synchronized boolean acquireLock() throws InterruptedException {
log.info(">>>>>>>>>> the name of distributed lock is {}", lockKey);
int timeout = TIMEOUT_MSECS;
while (timeout >= 0) {
long expires = System.currentTimeMillis() + expiredMsecs + 1;
String expiresStr = String.valueOf(expires);
log.info(">>>>>>>>>>the content of distributed lock is {}", expiresStr);
if (jedisClient.setnx(lockKey, expiresStr) == 1) {
log.info(">>>>>>>>>> acquire the distributed lock({}) immediately", lockKey);
locked = true;
return true;
}
String currValueStr = jedisClient.get(lockKey);
if (currValueStr != null && Long.parseLong(currValueStr) < System.currentTimeMillis()) {
String preValueStr = jedisClient.getSet(lockKey, expiresStr);
if (preValueStr != null && preValueStr.equals(currValueStr)) {
log.info(">>>>>>>>>> acquire the distributed lock({}) finally", lockKey);
locked = true;
return true;
}
}
timeout -= DEFAULT_ACQUIRE_MSECS;
Thread.sleep((long) (Math.random() * DEFAULT_ACQUIRE_MSECS));
}
return false;
}
/**
* 解锁
*/
public synchronized void releaseLock() {
if (locked) {
jedisClient.del(this.lockKey);
locked = false;
log.info("<<<<<<<<<< release the distributed lock({}) successfully", lockKey);
}
}
public String getLockKey() {
return lockKey;
}
public void setLockKey(String lockKey) {
this.lockKey = lockKey;
}
public int getExpiredMsecs() {
return expiredMsecs;
}
public void setExpiredMsecs(int expiredMsecs) {
this.expiredMsecs = expiredMsecs;
}
}
public void test(){
final String lockKey = Constants.APP_KEY.concat(Constants.ACT_SIGN_UP_KEY).concat(id);
RedisDistributedLock redisDistributedLock = SpringContextUtils.getBean(RedisDistributedLock.BEAN_NAME);
redisDistributedLock.setLockKey(lockKey);
try {
if (redisDistributedLock.acquireLock()) {
//TODO
}
} catch (InterruptedException e) {
log.error("异常,e=" + e.getMessage());
} finally {
redisDistributedLock.releaseLock();
}
}