您的位置:首页 > 数据库 > Redis

【redis】分布式锁

2017-02-15 16:07 148 查看
1)setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。

2.)get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。

3.)计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。

4.)判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。

5) 在获取到锁之后,当前线程可以开始做自增操作,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

上面是新方案,区别不大

基于redis的分布式锁,欢迎大家批评

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

@Component
public class DistributeLock {

@Resource(name = "enableRedis")
Redis redis;

/**
* 默认锁的超时时间,30s
*/
static final int DEFAULT_KEY_TIMEOUT = 30;

private void sleep() {
try {
Thread.sleep(200L);
} catch (InterruptedException e) {
}
}

/**
* 会一直阻塞,直到加锁成功
*
* @param key
*/
public void lock(String key) {
while (redis.setnx(key, "1") != 1) {
sleep();
}
redis.expire(key, DEFAULT_KEY_TIMEOUT);
}

/**
* 尝试加锁
*
* @param key
* @return 加锁失败返回false,or true
*/
public boolean tryLock(String key) {
boolean locked = redis.setnx(key, "1") == 1;
if (locked) {
redis.expire(key, DEFAULT_KEY_TIMEOUT);
}
return locked;
}

/**
* 尝试加锁,会在一段时间内重复加锁,直到加锁成功 或 超时
*
* @param key
* @param millis
*            尝试加锁时长,单位:秒
* @return 加锁失败返回false,or true
* @throws InterruptedException
*/
public boolean tryLock(String key, long millis) throws InterruptedException {
long deadline = System.currentTimeMillis() + millis;
while (redis.setnx(key, "1") != 1) {
sleep();
millis = deadline - System.currentTimeMillis();
if (millis <= 0L) {
// 超时,加锁失败
// 可以顺便检查该锁是不是没有设置超时时间
if (redis.ttl(key) < 0) {
// 以防,该锁没有设置超时时间
redis.expire(key, DEFAULT_KEY_TIMEOUT);
}
return false;
}
}
redis.expire(key, DEFAULT_KEY_TIMEOUT);
return true;
}

public void unlock(String key) {
redis.del(key);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: