public void updateHordeAdvertClickNum(HordeAdvertInfoRequest request) {
String lockKey = "HORDE_ADVERT_CLICK_KEY:" + request.getAdvertId();
RLock rLock = redisson.getLock(lockKey);
try {
boolean lock = rLock.tryLock(2L, TimeUnit.SECONDS);
if (lock) {
HordeAdvertInfoEntity entity = hordeAdvertInfoMapper.findById(request.getAdvertId());
MongoUpdateWrapper wrapper = new MongoUpdateWrapper();
Integer clickNum = entity.getClickNum()==null?0:entity.getClickNum();
wrapper.set(HordeAdvertInfoEntity::getClickNum, clickNum+1);
wrapper.and(HordeAdvertInfoEntity::getId).eq(request.getAdvertId());
hordeAdvertInfoMapper.update(wrapper);
} else {
throw BusinessException.newParamsException("获取锁失败!");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
rLock.unlock();
}
}
public void test() throws Exception{
RLock lock = redissonClient.getLock("guodong"); // 拿锁失败时会不停的重试
// 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s
lock.lock();
// 具有Watch Dog 自动延期机制 默认续30s
// 尝试拿锁10s后停止重试,返回false 具有Watch Dog 自动延期机制 默认续30s
boolean res1 = lock.tryLock(10, TimeUnit.SECONDS);
// 没有Watch Dog
// 尝试获取锁10秒,如果获取不到则放弃
lock.lock(10, TimeUnit.SECONDS);
// 没有Watch Dog
// 尝试获取锁,等待100秒,持有锁10秒钟
boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS);
Thread.sleep(40000L);
lock.unlock();
}
package com.flhy.redis.utils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* @author zengqingyu
* @Desc: 分布式锁工具类
*/
@Component
@Slf4j
public class RedissonLockUtil {
@Resource
private RedissonClient client;
private final static String SPLIT = "/";
/**
* 超时时间15秒(占有锁的最长时间)
*/
private final static Integer TIMEOUT = 15;
/**
* 获取业务锁
*
* @param prefix 业务号锁前缀
* @param businessNo 业务号
*/
public void lock(String prefix, String businessNo) {
RLock rLock = client.getLock(prefix + SPLIT + businessNo);
rLock.lock(TIMEOUT, TimeUnit.SECONDS);
}
/**
* 解锁
*
* @param prefix 业务号锁前缀
* @param businessNo 业务号
*/
public void unlock(String prefix, String businessNo) {
RLock rLock = client.getLock(prefix + SPLIT + businessNo);
try {
if (rLock.isHeldByCurrentThread()) {
rLock.unlock();
}
} catch (IllegalMonitorStateException e) {
log.error("RedissonLockUtil lock timeout unlock", e);
}
}
/**
* 尝试获取分布式锁,带有尝试获取锁的等待时间 和 占有锁之后的释放时间
*
* @param prefix 业务号前缀
* @param businessNo 业务号
* @param waitTime 这个参数决定了在尝试获取锁时的最长等待时间。当你的程序尝试获取锁时,如果锁已经被其他进程或线程持有,它会等待一段时间,直到锁变为可用状态。
* waitTime就是这个等待时间的上限。如果在这段时间内锁没有被释放,则获取锁的尝试会失败。这个参数有助于防止在锁资源上的长时间阻塞。
* @param leaseTime 这个参数表示一旦获取了锁之后,锁将会被保持多长时间。在leaseTime期满后,锁会自动被释放。
* 这是一种安全措施,以防止某个进程或线程在持有锁之后忘记释放它,或因为崩溃而无法释放,从而导致其他线程或进程永远无法获取这个锁。
* 设置合理的leaseTime可以确保即使出现这样的情况,锁最终也会被释放,从而使得其他进程能够获取锁。
* @return 是否抢锁成功,true:抢锁成功,false: 抢锁失败
*/
public boolean tryLockWithWaitTimeAndLeaseTime(String prefix, String businessNo, int waitTime, int leaseTime) {
RLock lock = client.getLock(prefix + SPLIT + businessNo);
try {
return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return false;
}
}
/**
* 尝试获取分布式锁,带有尝试获取锁的等待时间
*
* @param prefix 业务号前缀
* @param businessNo 业务号
* @param waitTime 使用场景:例如,抽奖,在1秒内若该用户没有抢锁成功,则给用户返回系统繁忙,请稍后再试的文案, 单位:秒
* 这个参数决定了在尝试获取锁时的最长等待时间。当你的程序尝试获取锁时,如果锁已经被其他进程或线程持有,它会等待一段时间,直到锁变为可用状态。
* waitTime就是这个等待时间的上限。如果在这段时间内锁没有被释放,则获取锁的尝试会失败。这个参数有助于防止在锁资源上的长时间阻塞。
* @return 是否抢锁成功, true: 抢锁成功, false: 抢锁失败
*/
public boolean tryLockWithWaitTime(String prefix, String businessNo, int waitTime) {
RLock lock = client.getLock(prefix + SPLIT + businessNo);
try {
return lock.tryLock(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return false;
}
}
/**
* 尝试获取分布式锁 抢锁失败后,不会等待,立即返回成功或失败
*
* @param prefix 业务号前缀
* @param businessNo 业务号,
* @return 使用场景:例如,抽奖,若该用户没有抢锁成功,则立即给返回用户系统繁忙,请稍后再试的文案
* 是否抢锁成功, true: 抢锁成功, false: 抢锁失败
*/
public boolean tryLock(String prefix, String businessNo) {
RLock lock = client.getLock(prefix + SPLIT + businessNo);
return lock.tryLock();
}
}