- 可重入锁(Reentrant Lock)
Redisson的分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口,同时还支持自动过期解锁。
public void testReentrantLock(RedissonClient redisson){
RLock lock = redisson.getLock("anyLock");
try{
// 1. 最常见的使用方法
//lock.lock();
// 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
//lock.lock(10, TimeUnit.SECONDS);
// 3. 尝试加锁,最多等待3秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
if(res){
//成功
// do your business
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
Redisson同时还为分布式锁提供了异步执行的相关方法:
public void testAsyncReentrantLock(RedissonClient redisson){
RLock lock = redisson.getLock("anyLock");
try{
lock.lockAsync();
lock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = lock.tryLockAsync(3, 10, TimeUnit.SECONDS);
if(res.get()){
// do your business
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
- 公平锁(Fair Lock)
Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock接口的一种RLock对象。在提供了自动过期解锁功能的同时,保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。
public void testFairLock(RedissonClient redisson){
RLock fairLock = redisson.getFairLock("anyLock");
try{
// 最常见的使用方法
fairLock.lock();
// 支持过期解锁功能, 10秒钟以后自动解锁,无需调用unlock方法手动解锁
fairLock.lock(10, TimeUnit.SECONDS);
// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fairLock.unlock();
}
}
Redisson同时还为分布式可重入公平锁提供了异步执行的相关方法:
RLock fairLock = redisson.getFairLock("anyLock");
fairLock.lockAsync();
fairLock.lockAsync(10, TimeUnit.SECONDS);
Future<Boolean> res = fairLock.tryLockAsync(100, 10, TimeUnit.SECONDS);
/*
* Copyright 2021 Wicrenet, Inc. All rights reserved.
*/
package com.allianity.modules.cms.cache.impl;
import com.allianity.common.learning.enums.RedisRouteKeyEnum;
import com.allianity.modules.cms.cache.UserCoursewareCache;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.LongCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* 【】
*
* @author yangjunxiong
* Created on 2021/1/14 11:42
*/
@Component
public class UserCoursewareCacheImpl implements UserCoursewareCache {
@Autowired
private RedissonClient redissonClient;
@Override
public Boolean setUserCoursewareDuration(Long userId, Long s) {
if (Objects.isNull(userId) || Objects.isNull(s)) {
return false;
}
RMapCache<String, Long> mapCache = redissonClient.getMapCache(RedisRouteKeyEnum.T_USER_COURSEWARE_DURATION.getKey(), LongCodec.INSTANCE);
mapCache.addAndGet(userId + "", s);
mapCache.expire(RedisRouteKeyEnum.ACTIVITY_AUDIENCE_INFO.getTTL0(), TimeUnit.SECONDS);
return true;
}
@Override
public Long getUserCoursewareDuration(Long userId) {
RMapCache<String, Long> mapCache = redissonClient.getMapCache(RedisRouteKeyEnum.T_USER_COURSEWARE_DURATION.getKey(), LongCodec.INSTANCE);
return mapCache.get(userId + "");
}
}
/*
* Copyright 2020 Wicrenet, Inc. All rights reserved.
*/
package com.allianity.modules.report.cache;
import com.allianity.common.learning.enums.RedisRouteKeyEnum;
import com.allianity.modules.report.controller.model.CourseGroupRateReportQuery;
import com.allianity.modules.report.dto.CourseGroupRateBycgIdDTO;
import com.allianity.modules.report.dto.CourseGroupRateReportByDeptIdDTO;
import com.allianity.modules.report.dto.ReportUserDto;
import com.allianity.modules.report.service.impl.AbsCourseGroupRateReportServiceImpl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.joda.time.LocalDateTime;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* 【 任务完成率 缓存层 】
*
* @author YJX
* Created on 2020/12/7 18:02
*/
@Primary
@Service
@Qualifier("cache")
public class CourseGroupRateReportCacheServiceImpl extends AbsCourseGroupRateReportServiceImpl {
@Autowired
private RedissonClient redissonClient;
@Autowired
@Qualifier("base")
private AbsCourseGroupRateReportServiceImpl absCourseGroupRateReportService;
@Override
public Page<CourseGroupRateReportByDeptIdDTO> pageingByDeptId(CourseGroupRateReportQuery query) {
RBucket<Page<CourseGroupRateReportByDeptIdDTO>> bucket = redissonClient.getBucket(RedisRouteKeyEnum.API_REPORT_COURSE_GROUP_RATE.getKey() + ":" + query.getStatisticsType() + ":" + query.getDeptId() + ":" + query.getPage() + ":" + query.getLimit() +":" + LocalDateTime.now().toString("yyyy-M-d"));
Page<CourseGroupRateReportByDeptIdDTO> page = bucket.get();
if (Objects.isNull(page)) {
page = this.absCourseGroupRateReportService.pageingByDeptId(query);
bucket.set(page);
bucket.expire(RedisRouteKeyEnum.API_REPORT_COURSE_GROUP_RATE.getTimeToLive(), TimeUnit.SECONDS);
}
return page;
}
}
private synchronized Boolean checkNub(String actId, String treeId) {
TreeSaplingEntity one = this.treeSaplingService.getOne(new LambdaQueryWrapper<TreeSaplingEntity>()
.eq(TreeSaplingEntity::getActId, actId)
.eq(TreeSaplingEntity::getTreeId, treeId)
.eq(TreeSaplingEntity::getDelFlag, 0)
.eq(TreeSaplingEntity::getStatus, 1)//是否有效
);
//可领取总数
Integer treeTotalNumber = one.getTreeTotalNumber();
//redis处理超领事件
RAtomicLong atomicLong = redissonClient.getAtomicLong(RedisRouteKeyEnum.TREE_ACTIVITY_TREE_ID_COUNT.getKey() + actId + "_" + treeId);
long sum = atomicLong.get();
if (sum == 0L) {
//已领取数量
sum = this.count(new LambdaQueryWrapper<TreeUserEntity>()
.eq(TreeUserEntity::getActId, actId)
.eq(TreeUserEntity::getTreeId, treeId)
.eq(TreeUserEntity::getDelFlag, 0)
);
atomicLong.expire(RedisRouteKeyEnum.TREE_ACTIVITY_TREE_ID_COUNT.getTimeToLive(), TimeUnit.SECONDS);
}
Boolean a = sum < treeTotalNumber;
if (a) {
//自增加1
sum = atomicLong.incrementAndGet();
}
return a;
}