概述
1、背景
目前是有很多个查询条件,比如版本(v3.90.1,v3.90.1,v3.90.2等),系统(安卓,ios),应用id等,希望按某个查询条件来锁定查询资源,可以使用ReentrantLock 来缩小锁的粒度。
2、使用
2.1 核心代码
private Map<String, LocalCacheEntry> map = new ConcurrentHashMap<>();
/**
* 使用java本地锁查询数据
*/
private SourceDataResult getDataByLocalLock(String mediaKey, AppSourceParam param) {
LocalCacheEntry resultEntry = map.compute(mediaKey, (k, entry) -> {
if (entry == null) {
entry = new LocalCacheEntry(mediaKey, param);
}
return entry;
});
SourceDataResult dataResult = resultEntry.loadData();
return dataResult;
}
/**
* java锁,限制锁的范围是mediaKey
*/
public class LocalCacheEntry {
private final ReentrantLock lock = new ReentrantLock();
private final String mediaKey;
private final AppSourceParam param;
public LocalCacheEntry(String mediaKey, AppSourceParam param) {
this.mediaKey = mediaKey;
this.param = param;
}
public SourceDataResult loadData() {
try {
int count = 0;
for (; ; ) {
count++;
if (lock.tryLock() || lock.tryLock(20, TimeUnit.MILLISECONDS)) {
SourceDataResult dataResult = mediaSourceCache.getIfPresent(mediaKey);
if (dataResult != null) {
logger.info("get lock and cache have data,mediaKey:{}", mediaKey);
return dataResult;
}
//查数据库
try (Jedis jedis = mediaSourceJedisPool.getResource()) {
List<SourceGroupVO> sourceGroups = SourceMediaServiceImpl.this.getDataFromDb(param);
SourceDataResult result = sourceListConvertMap(sourceGroups);
logger.info("get data from db,mediaKey:{}", mediaKey);
jedis.setex(mediaKey, SourceConstants.SOURCE_EXPIRE_TIME, JSONObject.toJSONString(result));
mediaSourceCache.put(mediaKey, result);
return result;
} catch (Exception e) {
logger.error("set data to redis error, param:{}", JSONObject.toJSONString(param), e);
} finally {
logger.info("release lock,mediaKey:{}", mediaKey);
lock.unlock();
}
} else if (SourceMediaServiceImpl.this.getDataResultFromRedis(mediaKey) != null) {
logger.info("not get lock but cache have data,mediaKey:{}", mediaKey);
break;
} else if (count >= 3) {
logger.info("the loop did not get data,mediaKey:{}", mediaKey);
return new SourceDataResult();
}
}
} catch (Exception e) {
logger.error("load data error,mediaKey:{}", mediaKey, e);
}
return SourceMediaServiceImpl.this.getDataResultFromRedis(mediaKey);
}
}
2.2 讲解
因为会有很多种查询条件,将每个条件组装成key,作为map的key,value是自定义的对象。将ReentrantLock锁住自定义的对象LocalCacheEntry ,这样能降低锁的粒度。for循环用死循环(自旋),lock.tryLock() || lock.tryLock(20, TimeUnit.MILLISECONDS) 是获取到锁或者等20ms获取到锁就执行查询(使用20ms的目的防止一直尝试获取锁,导致cpu飙高),否则判断redis是否有数据,有了则拿取数据,最后如果循环三次还未获取到数据,则返回空数据给前端。
最后
以上就是失眠金针菇为你收集整理的java ReentrantLock 怎么缩写锁的粒度的全部内容,希望文章能够帮你解决java ReentrantLock 怎么缩写锁的粒度所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复