1、定义redis实现分布式锁的接口
package com.iol.common.util.concurrent.locks;
import java.io.Serializable;
/**
* Description: 定义redis实现分布式锁的算法<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月8日
*
* @author 王鑫
* @version 1.0
*/
public interface IRedisLockArithmetic extends Serializable {
/**
* 加锁算法<br />
* @param key
* @return
*/
public boolean lock(String key);
/**
* 解锁算法<br />
* @param key
* @return
*/
public boolean unLock(String key);
}
2、redis分布式锁基础算法实现
package com.iol.common.util.concurrent.locks.arithmetic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.iol.common.util.concurrent.locks.IRedisComponent;
import com.iol.common.util.concurrent.locks.IRedisLockArithmetic;
/**
* Description: redis分布式锁基础算法实现<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月9日
*
* @author 王鑫
* @version 1.0
*/
public class RedisLockBaseArithmetic implements IRedisLockArithmetic {
/**
*serialVersionUID
*/
private static final long serialVersionUID = -8333946071502606883L;
private Logger logger = LoggerFactory.getLogger(RedisLockBaseArithmetic.class);
/**
* redis操作方法
*/
private IRedisComponent redisComp;
/**
* 超时时间,以毫秒为单位<br />
* 默认为5分钟
*/
private long overtime = 5 * 60 * 1000L;
/**
* 休眠时长,以毫秒为单位<br />
* 默认为100毫秒
*/
private long sleeptime = 100L;
/**
* 当前时间
*/
private long currentLockTime;
/**
* @param redisComp the redisComp to set
*/
public void setRedisComp(IRedisComponent redisComp) {
this.redisComp = redisComp;
}
/**
* @param overtime the overtime to set
*/
public void setOvertime(long overtime) {
this.overtime = overtime;
}
/**
* @param sleeptime the sleeptime to set
*/
public void setSleeptime(long sleeptime) {
this.sleeptime = sleeptime;
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#lock(java.lang.String, java.lang.Long)
*/
@Override
public boolean lock(String key) {
while(true) {
// 当前加锁时间
currentLockTime = System.currentTimeMillis();
if(redisComp.setIfAbsent(key, currentLockTime)) {
// 获取锁成功
logger.debug("直接获取锁{key: {}, currentLockTime: {}}", key, currentLockTime);
return true;
} else {
//其他线程占用了锁
logger.debug("检测到锁被占用{key: {}, currentLockTime: {}}", key, currentLockTime);
Long otherLockTime = redisComp.get(key);
if(otherLockTime == null) {
// 其他系统释放了锁
// 立刻重新尝试加锁
logger.debug("检测到锁被释放{key: {}, currentLockTime: {}}", key, currentLockTime);
continue;
} else {
if(currentLockTime - otherLockTime >= overtime) {
//锁超时
//尝试更新锁
logger.debug("检测到锁超时{key: {}, currentLockTime: {}, otherLockTime: {}}", key, currentLockTime, otherLockTime);
Long otherLockTime2 = redisComp.getAndSet(key, currentLockTime);
if(otherLockTime2 == null || otherLockTime.equals(otherLockTime2)) {
logger.debug("获取到超时锁{key: {}, currentLockTime: {}, otherLockTime: {}, otherLockTime2: {}}", key, currentLockTime, otherLockTime, otherLockTime2);
return true;
} else {
sleep();
//重新尝试加锁
logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);
continue;
}
} else {
//锁未超时
sleep();
//重新尝试加锁
logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);
continue;
}
}
}
}
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#unLock(java.lang.String)
*/
@Override
public boolean unLock(String key) {
logger.debug("解锁{key: {}}", key);
redisComp.delete(key);
return true;
}
/**
* 休眠<br />
* @param sleeptime
*/
private void sleep() {
try {
Thread.sleep(sleeptime);
} catch (InterruptedException e) {
throw new LockException("线程异常中断", e);
}
}
}
3、定义实际操作Redis的组件所使用的方法接口
package com.iol.common.util.concurrent.locks;
import java.io.Serializable;
/**
* Description: 定义实际操作Redis的组件所使用的方法<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月8日
*
* @author 王鑫
* @version 1.0
*/
public interface IRedisComponent extends Serializable {
/**
* 执行redis的SETNX命令
* @param key
* @param timeMillisecond
* @return
*/
public Boolean setIfAbsent(String key, Long timeMillisecond);
/**
* 执行redis的GET命令<br />
* @param key
* @return
*/
public Long get(String key);
/**
* 执行redis的GETSET命令<br />
* @param key
* @param timeMillisecond
* @return
*/
public Long getAndSet(String key, Long timeMillisecond);
/**
* 执行redis的DEL命令<br />
* @param key
* @return
*/
public void delete(String key);
}
4、spring实现的redis组件的方法
package com.iol.common.util.concurrent.locks.component;
import org.springframework.data.redis.core.RedisTemplate;
import com.iol.common.util.concurrent.locks.IRedisComponent;
/**
* Description: spring实现的redis组建<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月10日
*
* @author 王鑫
* @version 1.0
*/
public class SpringRedisComponent implements IRedisComponent {
/**
*serialVersionUID
*/
private static final long serialVersionUID = 3673851740133937797L;
private RedisTemplate<String, Long> redisTemplate;
/**
* @param redisTemplate the redisTemplate to set
*/
public void setRedisTemplate(RedisTemplate<String, Long> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisComponent#setIfAbsent(java.lang.String, java.lang.Long)
*/
@Override
public Boolean setIfAbsent(String key, Long timeMillisecond) {
return redisTemplate.opsForValue().setIfAbsent(key, timeMillisecond);
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisComponent#get(java.lang.String)
*/
@Override
public Long get(String key) {
return redisTemplate.opsForValue().get(key);
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisComponent#getAndSet(java.lang.String, java.lang.Long)
*/
@Override
public Long getAndSet(String key, Long timeMillisecond) {
return redisTemplate.opsForValue().getAndSet(key, timeMillisecond);
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisComponent#delete(java.lang.String)
*/
@Override
public void delete(String key) {
redisTemplate.delete(key);
}
}
5、创建RedisLock的工厂方法定义
package com.iol.common.util.concurrent.locks;
/**
* Description: 创建RedisLock的工厂方法定义<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月10日
*
* @author 王鑫
* @version 1.0
*/
public interface IRedisLockFactoryBean {
/**
* 工厂方法<br />
* @param key
*
* @return
*/
public RedisLock createLock(String key);
}
6、简单的RedisLock工厂类实现
package com.iol.common.util.concurrent.locks;
import org.apache.commons.lang3.StringUtils;
import com.iol.common.util.concurrent.locks.arithmetic.RedisLockBaseArithmetic;
/**
* Description: 简单的RedisLock工厂类<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月10日
*
* @author 王鑫
* @version 1.0
*/
public class SimpleRedisLockFactoryBean implements IRedisLockFactoryBean {
/**
* 操作redis的
*/
private IRedisComponent redisComponent;
/**
* 超时时间
*/
private String overtime;
/**
* 休眠时间
*/
private String sleeptime;
/**
* @param redisComponent the redisComponent to set
*/
public void setRedisComponent(IRedisComponent redisComponent) {
this.redisComponent = redisComponent;
}
/**
* @param overtime the overtime to set
*/
public void setOvertime(String overtime) {
this.overtime = overtime;
}
/**
* @param sleeptime the sleeptime to set
*/
public void setSleeptime(String sleeptime) {
this.sleeptime = sleeptime;
}
/* (non-Javadoc)
* @see com.iol.common.util.concurrent.locks.IRedisLockFactoryBean#createLock(java.lang.String)
*/
@Override
public RedisLock createLock(String key) {
RedisLockBaseArithmetic arithmetic = new RedisLockBaseArithmetic();
if(redisComponent != null) {
arithmetic.setRedisComp(redisComponent);
} else {
throw new RedisLockCreateException("redisComponent未初始化");
}
if(StringUtils.isNotEmpty(overtime)) {
arithmetic.setOvertime(Long.parseLong(overtime));
}
if(StringUtils.isNotEmpty(sleeptime)) {
arithmetic.setSleeptime(Long.parseLong(sleeptime));
}
RedisLock lock = new RedisLock(key, arithmetic);
return lock;
}
}
7、简单的使用spring-redis实现的分布式锁
package com.iol.common.util.concurrent.locks;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* Description: 简单的使用spring-redis实现的分布式锁<br />
* This program is protected by copyright simon-common.<br />
* Program Name: simon-common<br />
* Date: 2015年9月8日
*
* @author 王鑫
* @version 1.0
*/
public class RedisLock implements Lock, Serializable {
/**
*serialVersionUID
*/
private static final long serialVersionUID = 6278513934629913285L;
private IRedisLockArithmetic arithmetic;
private String key;
public RedisLock(String key, IRedisLockArithmetic arithmetic) {
this.key = key;
this.arithmetic = arithmetic;
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#lock()
*/
@Override
public synchronized void lock() {
arithmetic.lock(key);
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#unlock()
*/
@Override
public synchronized void unlock() {
arithmetic.unLock(key);
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#lockInterruptibly()
*/
@Override
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException("方法未实现");
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#tryLock()
*/
@Override
public boolean tryLock() {
throw new UnsupportedOperationException("方法未实现");
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#tryLock(long, java.util.concurrent.TimeUnit)
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException("方法未实现");
}
/* (non-Javadoc)
* @see java.util.concurrent.locks.Lock#newCondition()
*/
@Override
public Condition newCondition() {
throw new UnsupportedOperationException("方法未实现");
}
}
8、定义分布式锁异常
package com.iol.common.util.concurrent.locks;
/**
* Description: 分布式锁异常<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月9日
*
* @author 王鑫
* @version 1.0
*/
public class RedisLockException extends RuntimeException {
/**
*serialVersionUID
*/
private static final long serialVersionUID = 5781958965016402002L;
/**
* 创建RedisLockException
* @param msg
*/
public RedisLockException(String msg) {
super(msg);
}
/**
* 创建RedisLockException
* @param msg
* @param cause
*/
public RedisLockException(String msg, Throwable cause) {
super(msg, cause);
}
}
9、分布式锁异常实现
package com.iol.common.util.concurrent.locks;
/**
* Description: TODO<br />
* This program is protected by copyright IOL_SMALL_TAIL.<br />
* Program Name: IOL_SMALL_TAIL<br />
* Date: 2015年11月10日
*
* @author 王鑫
* @version 1.0
*/
public class RedisLockCreateException extends RedisLockException {
/**
*serialVersionUID
*/
private static final long serialVersionUID = -3294103499200541403L;
private static final String baseMsg = "RedisLock创建异常: %s";
/**
* 创建RedisLockCreateException
*/
public RedisLockCreateException(String msg) {
super(String.format(baseMsg, msg));
}
}