Java后端程序员面经(2-1. 缓存之本地缓存)
来源:互联网 发布:泰瑞克埃文斯生涯数据 编辑:程序博客网 时间:2024/05/29 16:41
说明
本文主要基于面试中碰到的问题进行总结分析,可能不全。
应用场景
1. 对数据一致性要求不强,主要是由于现在web服务一般是多机房部署2. 访问频繁,且更新不频繁的数据,前者体现了缓存的作用减少对DB的压力,后者说明了缓存毕竟是对DB数据的副本,如果经常不一致是肯定不行的3. 缓存的数据量不宜太大,毕竟单机内存还要分配来提供服务,不能太多给你当缓存使用了
技术思想
1. 需要一个装数据的容器,一般来说就是map2. 需要实现数据的读取和加载(将DB结果存入缓存)3. 有一定的策略对缓存数据进行失效(否则会导致长时间数据不一致性)4. 容器需要设置一个上限,并在达到上限时有一定的策略进行删除(见应用场景第三条)
具体实现
1. 自己实现 1-1. 申请一个ConcurrentHashMap(满了的策略不好实现)、或者LinkedHashMap(LRU好实现满了的策略,不过要自己加锁作线程安全)用作存储 1-2. 申请一个Timer()用作定时器,以实现定时对数据进行失效2. guava localCache 2-1. 引用 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency> 2-2.使用 private LoadingCache<String, Book> CACHE = CacheBuilder.newBuilder() .maximumSize(10) .refreshAfterWrite(10, TimeUnit.SECONDS) // 当缓存数据过期的时候,真正去加载数据的线程会阻塞一段时间,其余线程立马返回过期的值 .expireAfterAccess(15, TimeUnit.SECONDS) // 访问之后多久过期(删除此key的数据) .build( new CacheLoader<String, Book>() { @Override public Book load(String name) throws Exception { return bookDao.getByName(name); // 从DB中加载数据 } } ); 2-3. 调用 public Book getByName(String name) { return CACHE.getUnchecked(name); } 2-4. 参数refreshAfterWrite测试 private LoadingCache<String, Book> CACHE = CacheBuilder.newBuilder() .maximumSize(10) .refreshAfterWrite(10, TimeUnit.SECONDS) .expireAfterAccess(60, TimeUnit.SECONDS) .build( new CacheLoader<String, Book>() { @Override public Book load(String name) throws Exception { Book book = bookDao.getByName(name); System.out.println("c:\t" + LocalTime.now().getSecond() + book); return book; } } ); public Book getByNameWithCallable(String name) { Book result = null; try { result = CACHE.get(name, () -> { Book book = bookDao.getByName(name); System.out.println("a:\t" + LocalTime.now().getSecond() + book); try { Thread.sleep(5000); } catch (Exception ex) { } return book; }); System.out.println("b:\t" + LocalTime.now().getSecond() + result); } catch (ExecutionException e) { e.printStackTrace(); } return result; } 当多条线程调用时,第一条进行加载,其它的返回旧值,而且10s之后被访问就会触发刷新,即输出a那行。 第一个线程调用输出 { "id":5, "name":"wdmyong", "date":{ "year":2017, "month":"OCTOBER", "chronology":{ "id":"ISO", "calendarType":"iso8601" }, "era":"CE", "dayOfYear":290, "dayOfWeek":"TUESDAY", "leapYear":false, "dayOfMonth":17, "monthValue":10 }}第二条线程的输出{ "id": 4, "name": "wdmyong", "date": { "year": 2017, "month": "OCTOBER", "chronology": { "id": "ISO", "calendarType": "iso8601" }, "era": "CE", "dayOfYear": 290, "dayOfWeek": "TUESDAY", "leapYear": false, "dayOfMonth": 17, "monthValue": 10 }}我的id用了自增,可以看出在第一条线程计算的时候返回的是原来的id为4,等自己计算完之后,第一条线程返回的是id为5的数据。2-4. 上述过程应该还可以完全异步,即第一条计算线程也返回原值,让它异步计算自己计算去,后续待研究。3.
阅读全文
0 0
- Java后端程序员面经(2-1. 缓存之本地缓存)
- Java后端程序员面经(2-2. 缓存之分布式缓存)
- Java后端程序员面经(1-1. Java基础之集合篇)
- Java后端程序员面经(开篇)
- Android 之本地缓存
- java中的本地缓存
- java中的本地缓存
- java实现本地缓存
- java本地缓存实现
- 缓存之sdcard卡本地缓存
- java 缓存架构剖析--本地缓存(LoadingCache)
- Java后端程序员面经(1-2. Java基础之异常篇)
- guva 之数据库本地缓存
- ionic3基础之本地缓存
- Java 实现本地缓存工具
- 本地缓存
- 本地缓存
- 本地缓存
- jsp页面练习
- UVA-10954 Add All
- css的属性position
- 对字典类型的扩充
- java设计模式-01单例模式
- Java后端程序员面经(2-1. 缓存之本地缓存)
- 求字符数组的全排列
- java类集---foreach及Eumeration接口
- 高德地图
- 第六周
- 隐藏滚动条的方法
- c3p0配置模板
- Hbuilder启动夜神游模拟器失败,解决方案
- HDU 2066 一个人的旅行