loadingcache优化
问题分析
通过当前现场的火焰图进行分析
原本的loadingcache
public LoadingCache<Integer, Student> map = Caffeine.newBuilder().refreshAfterWrite(CONTRACT_CACHE_HOURS, TimeUnit.HOURS).maximumSize(CONTRACT_CONFIG_CACHE_SIZE).recordStats().build(key -> {try {Student condition = new Student();condition.setKey(key);List<Student> Students = studentMapper.selectBySelective(condition);return Students.stream().findFirst().orElse(null);} catch (Exception e) {//}return null;});
调用点
@Overridepublic Student getStudentByKey(Integer key) {if (null == key) {return null;}return map.get(key);}
原理分析,get在并发时会出现锁竞争
代码优化
查阅官方文档推荐使用buildAsync,替换掉get和build,修改后的代码如下
private static final ExecutorService CACHE_REFRESH_EXECUTOR = Executors.newFixedThreadPool(8);public AsyncLoadingCache<Integer, Student> map =Caffeine.newBuilder().refreshAfterWrite(CONTRACT_CACHE_HOURS, TimeUnit.HOURS).maximumSize(CONTRACT_CONFIG_CACHE_SIZE).recordStats().buildAsync((key, executor) -> CompletableFuture.supplyAsync(() -> {try {Student condition = new Student();condition.setKey(key);List<Student> students = studentMapper.selectBySelective(condition);return students.stream().findFirst().orElse(null);} catch (Exception e) {// }return null;}, CACHE_REFRESH_EXECUTOR));
AsyncLoadingCache的get是一个CompletableFuture,是异步加载
对比build和buildAsync的不同
通过源码可以看到buildAsync的cacheloader是一个AsyncCacheLoader
所以build在构造loadingcache的时候传入的是同步cacheloader,所以get就会出现锁等待;但是buildAsync在构造loadingcache的时候传入的是异步AsyncCacheLoader,所以get也是异步。