用Callable和CurrentHashMap实现排它锁
来源:互联网 发布:2013年旅游数据统计 编辑:程序博客网 时间:2024/05/16 05:05
在构建缓存的时候,不可避免的要使用排它锁,防止多个线程同时检测到没有缓存,而去查询数据库。此时一般情况下都会使用synchronized或者ReentrantLock来实现。今天给大家介绍一种比较巧妙的实现方式:使用Callable和CurrentHashMap来实现。
import java.util.concurrent.Callable;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import java.util.concurrent.FutureTask;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * 构建缓存时,增加排它锁,避免多个线程对同一个cacheKey同时访问数据库 * @author lizhiyang * */public class TaskUtils {private TaskUtils() {}private static final Logger logger = LoggerFactory.getLogger(TaskUtils.class); /** * 任务缓存map,key是加锁的键值,value需要加锁的代码(用线程来实现) */ private static final ConcurrentMap<String, FutureTask<Object>> taskHolder = new ConcurrentHashMap<String, FutureTask<Object>>(); /** * 确保整个jvm只有一个任务在执行 * @param cacheKey * @param caller * @return */ @SuppressWarnings("unchecked") public static <E> E getInTask(String cacheKey, Callable<E> caller) {// 建立运行的任务FutureTask<Object> ft = new FutureTask<Object>((Callable<Object>) caller);// 检查缓存是否有缓存在运行FutureTask<Object> t = taskHolder.putIfAbsent(cacheKey,(FutureTask<Object>) ft);if (t == null) {// 计算结果ft.run();t = ft;}try {E result = (E) t.get();return result;} catch (InterruptedException ie) {logger.warn("Task was interrupted. msg=" + ie.getMessage());} catch (Exception e) {logger.error("getInTask error", e);} finally {taskHolder.remove(cacheKey, t);}// 发生异常时,返回nullreturn null; }}使用方式如下:
使用://创建Callable,执行数据库查询操作Callable<List<Long>> caller = new Callable<List<Long>>() { public List<Long> call() throws InterruptedException {//查询数据库之前再次判断缓存中是否存在值 List<Long> goodsIdList = spyMemClient.get(cacheKey); if (goodsIdList != null) { LOG.info(new JsonLog("public rec by cache").put("cacheKey", cacheKey).toString()); return goodsIdList; } if(cacheProxy.containsDbNotHit(cacheKey)) { LOG.debug("public rec by cache contains db not hit : "+cacheKey); return Collections.emptyList(); }//缓存中不存在相应值,查询数据库 Map<String, String> parameters = new HashMap<String, String>(); parameters.put("city", strCityName); parameters.put("amount", String.valueOf(amount)); List<String> goodsIdStrList = mobileService.getPublicRecList(parameters); goodsIdList = dcodeGoodsId(goodsIdStrList); if(goodsIdList == null || goodsIdList.isEmpty()) { cacheProxy.setDbNotHit(cacheKey); LOG.debug("public rec by db set db not hit : "+cacheKey); } else { cacheProxy.cacheRecResult(cacheKey, goodsIdList); LOG.info(new JsonLog("public rec by db").put("cacheKey", cacheKey).toString()); } return goodsIdList; } }; //真实调用 goodsIdList = TaskUtils.getInTask(cacheKey, caller);
另外:在做缓存的时候,最好能够把缓存的时间进行离散化处理,否则会造成大量缓存在同一时间点失效,同时去访问数据库,瞬间数据库压力剧增。一般情况下,可以使用Memcached和Redis来做缓存,功能非常强大,操作也很简单。
0 0
- 用Callable和CurrentHashMap实现排它锁
- ZooKeeper分布式排它锁实现
- 5.zk实现-分布式排它锁
- MSSQL 共享锁和排它锁
- 共享锁和排它锁
- 什么是共享锁和排它锁
- 排它锁和共享锁
- 共享锁(S锁)和排它锁(X锁)
- 共享锁和排它锁(ReentrantReadWriteLock)
- Oracle的共享锁和排它锁
- mysql中的共享锁和排它锁
- Shared and Exclusive Locks 共享和排它锁
- currenthashmap
- currentHashMap
- 排它锁,共享锁,乐观锁,排它锁
- 共享锁&排它锁
- 无法获得排它锁
- 用Callable和Future实现多线程文件搜索
- 博客第一篇
- Unity3D 导入脚本のAnimation动画切割
- android studio 常遇错误,界面,Gradle详细讲解
- Objc中block的实现
- javascript 发送http请求
- 用Callable和CurrentHashMap实现排它锁
- 多终端WEB页面字体处理方法总结
- UILabel根据内容自动调整高度
- 文章标题
- 阿里云监控用户手册
- 安装和配置jenkins
- 微信公众帐号开发教程第17篇-应用实例之智能翻译
- 斯坦福大学iOS应用开发教程学习笔记(第二课) 计算器实现2 改进版
- weblogic的集群与配置