实际开发中,当系统是分布式集群情况下,多个请求对一条数据进行更新时,为了数据安全,我们必须要将这条数据锁住,但是集群负载情况下使用jdk自带的锁此时已经无济于事。我们必须要使用数据库锁。下面是基于redis实现的分布式锁简单案例。
1、锁接口
/**
* 分布式锁
* @author zhanglei
*/
public interface YBLock {
/**
* 获取锁
* @return boolean
*/
boolean acquire();
/**
* 释放锁
*/
void release();
}
2、回调接口
/**
* 获取锁失败,回调接口
*
* @author zhanglei
*/
public interface LockBack {
void fallback(RedisLock redisLock);
}
3、redis锁实现
/**
* redis分布式锁实现
*
* 锁本身并不是线程安全的,使用请在函数内部创建新的锁实例使用。
*
* @author zhanglei
*/
@SuppressWarnings("unchecked")
public class RedisLock implements YBLock{
private static Logger logger = LoggerFactory.getLogger(RedisLock.class);
/**
* redisTemplate
*/
private RedisTemplate redisTemplate;
/**
* 获取锁失败,回调
*/
private LockBack lockBack;
/**
* 锁字符串
*/
private String lockKey;
/**
* 锁过期时间 默认10秒 放置程序故障导致的锁永久不释放 单位毫秒
*/
private int expireTime = 1000 * 10;
public RedisLock(String lockKey){
this.lockKey = lockKey;
synchronized (RedisLock.class){
if(redisTemplate == null){
redisTemplate = SpringContext.getBean(StringRedisTemplate.class);
}
}
}
public RedisLock(String lockKey,int expireTime){
this(lockKey);
this.expireTime = expireTime;
}
public RedisLock(String lockKey,int expireTime,LockBack lockBack){
this(lockKey,expireTime);
this.lockBack = lockBack;
}
public RedisLock(String lockKey, LockBack lockBack){
this(lockKey);
this.lockBack = lockBack;
}
/**
* 获取锁
*/
@Override
public boolean acquire() {
//过期时间值
String expire = Long.toString(System.currentTimeMillis() + this.expireTime);
try {
while (true) {
//在redis中设置值
boolean acq = redisTemplate.opsForValue().setIfAbsent(this.lockKey, expire);
//设置成功
if (acq) {
logger.info("get redis lock success!");
//设置过期时间
redisTemplate.expire(this.lockKey, expireTime, TimeUnit.MILLISECONDS);
return true;
}
//如果获取锁失败,调用回调
if (this.lockBack != null) {
this.lockBack.fallback(this);
return false;
}
//睡眠100毫秒
Thread.sleep(100);
}
}catch (Exception e){
logger.error(e.getMessage(),e);
}
return false;
}
/**
* 释放锁
*/
@Override
public void release() {
this.redisTemplate.delete(this.lockKey);
}
public String getLockKey() {
return lockKey;
}
public void setLockKey(String lockKey) {
this.lockKey = lockKey;
}
public int getExpireTime() {
return expireTime;
}
public void setExpireTime(int expireTime) {
this.expireTime = expireTime;
}
}
4、获取锁工具类
/**
* 获取锁
*/
public final class LockUtil {
private static final String LOCK_KEY_NULL = "lock key not null";
private LockUtil(){}
public static RedisLock getLock(String lockKey){
Assert.notEmpty(LOCK_KEY_NULL,lockKey);
return new RedisLock(lockKey);
}
public static RedisLock getLock(String lockKey,LockBack lockBack){
Assert.notEmpty(LOCK_KEY_NULL,lockKey);
return new RedisLock(lockKey,lockBack);
}
public static RedisLock getLock(String lockKey,int expire){
Assert.notEmpty(LOCK_KEY_NULL,lockKey);
return new RedisLock(lockKey,expire);
}
public static RedisLock getLock(String lockKey,int expire,LockBack lockBack){
Assert.notEmpty(LOCK_KEY_NULL,lockKey);
return new RedisLock(lockKey,expire,lockBack);
}
}
以上代码可以实现简单的分布式锁