synchronied
场景:数据存入redis,并读取缓存。app用户读取,量较大
逻辑
1.先读取缓存,判断缓存中是否有值,有返回,无,继续执行
2.对当前缓存类(CacheTemplateService)对象(this)加锁
3.再次从缓存中获取数据,再次判断,有数据返回,无,继续执行
为什么这里再次判断缓存中是否有锁,加入不判断,如果有大量请求等待持有锁(在synchronized处等待),当持有锁线程执行结束后(已写入缓存),就会有另外一个线程进入同步代码块,又会去查询数据库,写入缓存,其实是多余的,加了再次加缓存判断,即可避免。
4.执行查询数据库逻辑
5.写缓存
工具类
@Slf4j @Component public class CacheTemplateService { @Autowired private RedisManager redisManager; publicT fetchCache(String key, Integer expire, TypeReference clazz, CacheLoadable cacheLoadable) { String json = (String) redisManager.get(key); if (Objects.nonNull(json) && StringUtils.isNotBlank(json) && !json.equalsIgnoreCase("null") && !"[]".equals(json) && !"{}".equals(json)) { return JSON.parseObject(json, clazz); } synchronized (this) { json = (String) redisManager.get(key); if (Objects.nonNull(json) && StringUtils.isNotBlank(json) && !json.equalsIgnoreCase("null") && !"[]".equals(json) && !"{}".equals(json)) { return JSON.parseObject(json, clazz); } // 核心业务 T result = cacheLoadable.load(); redisManager.put(key, expire, JSON.toJSonString(result)); return result; } } public void invalidate(String key) { redisManager.remove(key); } }
调用代码
ListresLiveVOS = cacheTemplateService .fetchCache(RedisEnum.ADVANCE_LIVE_KEY.key, RedisEnum.ADVANCE_LIVE_KEY.expired, new TypeReference >() { }, new CacheLoadable
>() { @Override public List
load() { return selectAdvanceLive(uid); } });
Lock
场景:类似第一种场景,也是先从缓存查询数据,没有会调用第三方接口数据,app用户读取,量较大
逻辑
1.读缓存,无,继续
2.加lock锁
3.再次查询缓存 double check
4.调第三方接口,查询数据
5.写入缓存
@Override public FundCompositeDTO fundCompositeData(String code) { if (StringUtils.isBlank(code)) { return null; } String key = RedisKeyHelper.compositeKey(code); FundCompositeDTO cacheData = (FundCompositeDTO) redis.get(key); if (cacheData != null) { return cacheData; } try { lock.tryLock(LOCK_TIMEOUT, TimeUnit.SECONDS); cacheData = (FundCompositeDTO) redis.get(key); if (cacheData != null) { return cacheData; } FundCompositeDTO dto = fetchFundCompositeDataFromDB(code); if (dto != null) { int expire = (int) DateTimeUtils.getCurrent2EndDiffSenconds(); float lastScore = getsetLastTotalScore(code, dto.getTotalScore()); dto.setFlag(dto.getTotalScore() > lastScore); redis.put(key, expire, dto); } return dto; } catch (Exception e) { log.info("Try Lock failed for the code#{}", code, e); return fetchFundCompositeDataFromDB(code); } finally { lock.unlock(); } }
比较二者
执行逻辑基本一样
Lock比较好吗,
lock获取锁有个时间限制(多久,与加锁内容执行时间有关),其他线程等待超时就放弃获取锁。
synchronized呢,经过锁升级过程,效率有所提升。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)