Guava Cache特性:对于同一个key,只让一个请求回源load数据,其他线程阻塞等待结果
2016-12-06 19:48
776 查看
设想高并发下的一种场景:假设我们将name=aty存放到缓存中,并设置的有过期时间。当缓存过期后,恰好有10个客户端发起请求,需要读取name的值。使用Guava Cache可以保证只让一个线程去加载数据(比如从数据库中),而其他线程则等待这个线程的返回结果。这样就能避免大量用户请求穿透缓存。
上面输出结果可以看到:只有一个线程去数据库中加载数据,其他线程都在等待(每个线程都耗时2s)。使用Guava确实可以做到:对于同一个key,无论有多少请求,都只会允许一个线程去加载数据。
但是也有一个很致命的缺陷:上面8个线程中,有一个线程实际去加载数据,其余7个线程都被阻塞了。如果能做到,当一个线程去加载数据,其余线程发现这个数据正在加载中,那么直接读取老的数据,这样就不会阻塞了。既然是缓存,读取旧一点数据也没有多大问题,却可以提高系统吞度量。
import com.google.common.base.Stopwatch; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class Main { // 1s无访问则缓存过期, 每次加载一个key需要耗时2s private static LoadingCache<String, String> cache = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS) .build(new CacheLoader<String, String>() { @Override public String load(String key) throws Exception { System.out.println("begin to query db..."); Thread.sleep(2000); System.out.println("success to query db..."); return UUID.randomUUID().toString(); } }); private static CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) throws Exception { cache.put("name", "aty"); Thread.sleep(1500); for (int i = 0; i < 8; i++) { startThread(i); } // 让线程运行 latch.countDown(); } private static void startThread(int id) { Thread t = new Thread(new Runnable() { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + "...begin"); latch.await(); Stopwatch watch = Stopwatch.createStarted(); System.out.println("value..." + cache.get("name")); watch.stop(); System.out.println(Thread.currentThread().getName() + "...finish,cost time=" + watch.elapsed(TimeUnit.SECONDS)); } catch (Exception e) { e.printStackTrace(); } } }); t.setName("Thread-" + id); t.start(); } }
上面输出结果可以看到:只有一个线程去数据库中加载数据,其他线程都在等待(每个线程都耗时2s)。使用Guava确实可以做到:对于同一个key,无论有多少请求,都只会允许一个线程去加载数据。
但是也有一个很致命的缺陷:上面8个线程中,有一个线程实际去加载数据,其余7个线程都被阻塞了。如果能做到,当一个线程去加载数据,其余线程发现这个数据正在加载中,那么直接读取老的数据,这样就不会阻塞了。既然是缓存,读取旧一点数据也没有多大问题,却可以提高系统吞度量。
相关文章推荐
- 在项目某个action方法中打个断点,当发一个请求在当前断点停住时,再发起其他请求,为什么会一直等待
- jmeter添加http请求、java请求,将返回的json数据提取出来并将结果追加到一个文件
- 求实数的绝对值。输入数据有多组,每组占一行,每行包含一个实数。对于每组输入数据,输出它的绝对值,要求每组数据输出一行,结果保留两位小数。
- Guava Cache特性:refreshAfterWrite只阻塞回源线程,其他线程返回旧值
- 返回结果一般如下: LAST_ACK 5 (正在等待处理的请求数) SYN_RECV 30 ESTABLISHED 1597 (正常数据传输状态) FIN_WAIT1 51 FIN_WAIT2 50
- ext异步请求一个aspx/ashx/web service取得数据,服务端返回一个json.然后客户端接收并显示.
- 用xmlHttp来做一个异步请求数据里例子
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 由于您和其他用户试图同时改变同一数据,导致 Microsoft Jet 数据库引擎停止进程。解决方法
- 转:邹建-- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 一个发送xml远程请求和接收xml请求结果并置入DataSet的方法
- 以下这段代码是一个内存缓存,对于数据较少时很有用
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 今天碰到了一个问题,数据传到数据库为空,结果没有注意,调试了好久
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 对于orale中的表数据类型的一个简单例子
- 使用事务与锁,实现一个用户取过的数据不被其他用户取到
- 我要从com向应用程序返回一个结构,结构中包括二进制数据,请问用什么方式传替比较好呢?BSTR,VARIANT还是其他什么类型比较好呢