logo头像
Snippet 博客主题

技术经验高并发总结第一篇

本文于 634 天之前发表,文中内容可能已经过时。

FutureTask的使用

场景一

我这边需要提供一个接口给客户端,这个接口需要请求外部接口20次,在这种场景下,我需要如何设计我的这个接口?

解决方案java篇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<FutureTask<List<String>>> tasks=new ArrayList<>(10);
for(int i=0;i<repeat;i++){
FutureTask<List<String>> futureTask = new FutureTask<>(() -> mobileComponent.getMobileList(numProvinceCode, numCityCode, req.getSearchValue()));
threadPoolTaskExecutor.execute(futureTask);
tasks.add(futureTask);
}
tasks.forEach(task->{
try {
mobileList.addAll(task.get());
} catch (InterruptedException e) {
log.error("获取手机号码 失败,请求串= {}", JSON.toJSONString(req),e);
} catch (ExecutionException e) {
log.error("获取手机号码 失败 = {}", JSON.toJSONString(req),e);
}
});

长短缓存的使用

场景一

在高并发场景中,如何防止缓存穿透的问题,如果没想清楚的情况下,可能认为加锁就能解决问题了,但在锁失效的情况下,其实还是没办法保证有多少的线程在锁失效的情况下落到了db里面,这就是一个考验运气的问题.,所以需要用到长短缓存去既能保证数据更新的实时性,又能保证不管在如何的高并发下,落到db的查询永远只有一条,这才能真正解决缓存穿透导致雪崩的问题.

解决方案java篇
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public boolean isBlack(Long cardId, Integer areaCode) {
String shortKey = "cache_card_black_short_" + cardId;
String longKey = "cache_card_black_long_" + cardId;
List<Integer> areaCodes;
if (redisTemplate.hasKey(shortKey)) {
//先从短缓存里面获取数据
areaCodes = (List<Integer>) redisTemplate.opsForValue().get(shortKey);
} else {
Lock lock = redisson.getLock(LockPrefix.CARD_BLACK_AREA + cardId);
//如果获取到锁,从数据库里面获取数据,放到长短缓存里面
if (lock.tryLock()) {
try {
areaCodes = refresh(cardId, shortKey, longKey);
} finally {
lock.unlock();
}
} else {
if (redisTemplate.hasKey(longKey)) {
areaCodes = (List<Integer>) redisTemplate.opsForValue().get(longKey);
} else {
Lock longLock = redisson.getLock(LockPrefix.CARD_BLACK_AREA_LONG + cardId);
try {
longLock.lock();
areaCodes = refresh(cardId, shortKey, longKey);
} finally {
longLock.unlock();
}
}

}
}
return areaCodes.contains(areaCode);
}

private List<Integer> refresh(Long cardId, String shortKey, String longKey) {
List<CardBlackArea> blackAreas = this.baseMapper.lambdaQuery().eq(CardBlackArea::getCardId, cardId).list();
List<Integer> areaCodes = blackAreas.stream().map(a -> a.getAreaCode()).collect(Collectors.toList());
redisTemplate.opsForValue().set(shortKey, areaCodes, 5, TimeUnit.MINUTES);
redisTemplate.opsForValue().set(longKey, areaCodes, 1, TimeUnit.DAYS);
return areaCodes;
}