public interface DistributedLock {
/**
* 加锁
* @param lockKey 锁定的key
* @param lockSeconds 锁定时间(单位:秒),超过该锁定时间会自动释放锁,可能会导致并发问题。
* @param expirySeconds 本次获取锁请求失效时间(单位:秒)
* @param sleepMillisecond 本次获取锁失败,等到多少毫秒再次尝试获取(单位:毫秒)
* @return 返回值大于0,则说明获取到锁,调用者需要保留该值,并在解锁时传入。
*/
public Long lock(String lockKey,long lockSeconds, long expirySeconds, int sleepMillisecond);
/**
* 解锁
* @param lockKey 锁定的key
*/
public void unlock(String lockKey,long lockValue);
}
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.aaron.redis.lock.DistributedLock;
@Service("redisDistributedLock")
public class RedisDistributedLockImpl implements DistributedLock {
private static final Logger LOG = LoggerFactory.getLogger(RedisDistributedLockImpl.class);
/**
* 锁定超时时间60秒, 单位毫秒, 意味着加锁期间内执行完操作 如果未完成会自动过期释放锁,造成并发问题。
*/
private static final long DEFAULT_LOCK_TIMEOUT = 60 * 1000;
@Autowired
protected StringRedisTemplate stringRedisTemplate;
@Override
public Long lock(String lockKey, long lockSeconds, long expirySeconds, int sleepMillisecond) {
Long lockVal = 0L;
long currMs = System.currentTimeMillis();
if (lockSeconds > 0L) {
lockSeconds = lockSeconds * 1000;
} else {
lockSeconds = DEFAULT_LOCK_TIMEOUT;
}
while (true) {
Long nextmin = getNextMin();
boolean lockResult = stringRedisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(lockKey.getBytes(), String.valueOf(nextmin).getBytes());
}
});
if (lockResult) {// 获得锁
LOG.debug("+++key:{} lock success", lockKey);
stringRedisTemplate.expire(lockKey, lockSeconds, TimeUnit.MILLISECONDS); // 设置超时时间,释放内存
lockVal = nextmin;
break;
} else {
// 调用get
String lockTimeObj = stringRedisTemplate.opsForValue().get(lockKey); // redis里的时间
if (null != lockTimeObj) {
Long ts = Long.valueOf(lockTimeObj);
long nowTs = System.currentTimeMillis();
if (nowTs - ts >= 0) {// 锁已经失效
// 调用getset,获取旧值,写入新值,获取不到值为null
long nextminVal = getNextMin();
String lockTimeObj1 = stringRedisTemplate.opsForValue().getAndSet(lockKey,
String.valueOf(nextminVal));
if (null == lockTimeObj1 || lockTimeObj.equals(lockTimeObj1)) {
stringRedisTemplate.expire(lockKey, lockSeconds, TimeUnit.MILLISECONDS); // 设置超时时间,释放内存
lockVal = nextminVal;
break;
}
}
}
if (lockVal == 0L) {
if (checkTimeout(currMs, expirySeconds)) {
break;
}
sleep(sleepMillisecond);
}
}
}
return lockVal;
}
@Override
public void unlock(String lockKey, long lockValue) {
if (lockValue <= 0L) {
return;
}
String objVal = stringRedisTemplate.opsForValue().get(lockKey);
if (objVal != null && objVal.equals(String.valueOf(lockValue))) {
stringRedisTemplate.delete(lockKey); // 删除键
LOG.debug("+++key:{} release success", lockKey);
}
}
private boolean checkTimeout(long currMs, long expirySeconds) {
return (System.currentTimeMillis() - currMs) > (expirySeconds * 1000);
}
private long getNextMin() {
return System.currentTimeMillis() + 60000;
}
private void sleep(int ms) {
try {
if (ms <= 0) {
ms = 50;
}
Thread.sleep(ms);
} catch (InterruptedException e) {
}
}
}
//lockKey
String lockKey = "lockKey"; //key
//获取到锁,则锁定30秒
long lockSeconds = 30;
//请求200秒如果还没获取到锁就超时返回
long expirySeconds = 0;
//未获取到锁,则休息30毫秒然后重试,直到expirySeconds过期
int sleepMillisecond = 30;
//获取锁
long lockVal = redisDistributedLock.lock(lockKey, lockSeconds, expirySeconds, sleepMillisecond);
//获取锁成功
if(lockVal > 0L){
try{
//执行逻辑
}catch (Exception e){
}finally{
//释放锁
redisDistributedLock.unlock(lockKey, lockVal);
}
}else{
//获取锁失败
}
}