我介绍一下Redis分布式锁吧:
一、定义redis实现分布式锁的接口
[java] view plain copy print?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)
}
二、redis分布式锁基础算法实现
[java] view plain copy print?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)
}
}
}
package com.markor.zest.commonredis.utils
import lombok.extern.slf4j.Slf4j
import org.redisson.api.RLock
import org.redisson.api.RedissonClient
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.transaction.support.TransactionSynchronization
import org.springframework.transaction.support.TransactionSynchronizationManager
import java.util.concurrent.TimeUnit
/**
* @Author: lining
* @Description: redis加锁工具类
* @Date: create in 2021/12/24 16:38
*/
@Slf4j
@SuppressWarnings("ALL")
@Component
public class RedissonTemplate {
@Autowired
private RedissonClient redissonClient
/**
* 尝试加锁
*
* @param lockName 锁名字
* @param waitTime 等待时间
* @param releaseTime 释放时间
* @param timeUnit 单位
* @param callBack 返回对象
* @param <T> 泛型
* @return 返回
*/
public T tryLock(String lockName,long waitTime,long releaseTime,TimeUnit timeUnit,RedissonLockCallBack callBack) {
RLock rLock =redissonClient.getLock(lockName)
T result =null
try {
boolean tryLock =this.tryLock(rLock, waitTime, releaseTime, timeUnit)
if (tryLock) {
this.unlock(rLock)
log.info("{}取到锁", lockName)
result = callBack.execute()
}else {
log.info("{}等待超时", lockName)
}
}catch (InterruptedException e) {
log.error("{} 锁发生中断异常!", lockName, e)
Thread.currentThread().interrupt()
}finally {
// 如果当前没有事务,且锁着呢,且是当前线程的
if (!TransactionSynchronizationManager.isActualTransactionActive() &&
rLock.isLocked() &&rLock.isHeldByCurrentThread()) {
rLock.unlock()
}
}
return result
}
/**
* 真正的加锁
*
* @param rLock 锁对象
* @param waitTime 等待时间
* @param releaseTime 释放时间
* @param timeUnit 单位
* @return 返回
*/
private boolean tryLock(RLock rLock,long waitTime,long releaseTime,TimeUnit timeUnit)throws InterruptedException {
boolean bool
if (waitTime >0 &&releaseTime >0) {
bool = rLock.tryLock(waitTime, releaseTime, timeUnit)
}else if (releaseTime >0) {
bool = rLock.tryLock(0, releaseTime, timeUnit)
}else if (waitTime >0) {
bool = rLock.tryLock(waitTime, timeUnit)
}else {
bool = rLock.tryLock()
}
return bool
}
/**
* redis解锁
*
* @param rLock 锁对象
*/
public void unlock(RLock rLock) {
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
log.info("{}释放锁",rLock.getName())
if (rLock.isLocked() &&rLock.isHeldByCurrentThread()) {
rLock.unlock()
}
}
})
}
}
}