前言
在Java并发编程中,我们通常使用到synchronized 、Lock这两个线程锁,Java中的锁,只能保证对同一个JVM中的线程有效。而在分布式集群环境,这个时候我们就需要使用到分布式锁。
实现分布式锁的方案:
·基于数据库实现分布式锁
·基于缓存Redis实现分布式锁
·基于Zookeeper的临时序列化节点实现分布式锁
Redis实现分布式锁
场景:在高并发的情况下,可能有大量请求来到数据库查询三级分类数据,而这种数据不会经常改变,可以引入缓存来存储第一次从数据库查询出来的数据,其他线程就可以去缓存中获取数据,来减少数据库的查询压力。
在集群的环境下,就可以使用分布式锁来控制去查询数据库的次数。
阶段一
private Map> getCatalogJsonDBWithRedisLock() {
// 去Redis中抢占位置
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "1111");
if (lock){
// 抢到锁了 执行业务
Map> dataFromDb = getDataFromDb();
// 删除锁
stringRedisTemplate.delete("lock");
return dataFromDb;
}else {
// 自旋获取锁
// 休眠100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return getCatalogJsonDBWithRedisLock();
}
}
得到锁以后,我们应该再去缓存中确定一次,如果没有才需要继续查询,从数据库查到数据以后,应该先把数据放入缓存中,再将数据返回。
private Map> getDataFromDb() {
// 得到锁以后,我们应该再去缓存中确定一次,如果没有才需要继续查询
String catalogJson = stringRedisTemplate.opsForValue().get("catalogJson");
if (!StringUtils.isEmpty(catalogJson)) {
// 反序列化 转换为指定对象
Map> result = JSON.parseObject(catalogJson, new
TypeReference>>() {});
return result;
}
System.out.println("查询数据库了......");
// 查询所有分类数据在进行刷选
List categoryEntityList = baseMapper.selectList(null);
// 查询一级分类
List leave1Categorys = getParent_cid(categoryEntityList, 0L);
Map> listMap = leave1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), l1 -> {
List categoryL2List = getParent_cid(categoryEntityList, l1.getCatId());
List catelog2Vos = null;
if (categoryL2List != null) {
catelog2Vos = categoryL2List.stream().map(l2 -> {
Catelog2Vo catelog2Vo = new Catelog2Vo(l2.getParentCid().toString(), null, l2.getCatId().toString(), l2.getName());
List categoryL3List = getParent_cid(categoryEntityList,
l2.getCatId());
if (categoryL3List != null) {
List catelog3Vos =
categoryL3List.stream().map(l3 -> {
Catelog2Vo.Catelog3Vo catelog3Vo = new
Catelog2Vo.Catelog3Vo(l2.getCatId().toString(),
l3.getCatId().toString(),
l3.getName());
return catelog3Vo;
}).collect(Collectors.toList());
catelog2Vo.s