guava LoadingCache学习
简介
使用Guava Cache可以保证只让一个线程去加载数据(比如从数据库中),而其他线程则等待这个线程的返回结果。这样就能避免大量用户请求穿透缓存。
但是也有一个很致命的缺陷:如果缓存过期,恰好有多个线程读取同一个key的值,那么guava只允许一个线程去加载数据,其余线程阻塞。这虽然可以防止大量请求穿透缓存,但是效率低下。使用refreshAfterWrite可以做到:只阻塞加载数据的线程,其余线程返回旧数据。
expireAfterWrite是在指定项在一定时间内没有创建/覆盖时,会移除该key,下次取的时候从loading中取
expireAfterAccess是指定项在一定时间内没有读写,会移除该key,下次取的时候从loading中取
refreshAfterWrite是在指定时间内没有被创建/覆盖,则指定时间过后,再次访问时,会去刷新该缓存,在新值没有到来之前,始终返回旧值。缓存项只有在被检索时才会真正刷新
跟expire的区别是,指定时间过后,expire是remove该key,下次访问是同步去获取返回新值
而refresh则是指定时间后,不会remove该key,下次访问会触发刷新,新值没有回来时返回旧值
但是对于系统启动阶段,还是存在问题。系统启动后,由于缓存没有数据,导致一个线程去加载数据的时候,别的线程依然都阻塞了(因为没有旧值可以返回)。所以一般系统启动的时候,我们需要将数据预先加载到缓存,不然就会出现这种情况。
还有一个问题,真正加载数据的那个线程一定会阻塞,我们希望这个加载过程是异步的。