caffeine: Java 8高性能缓存库包
Caffeine提供一个in-memory缓存,类似Google Guava的API,在Guava基础上提高了各种体验。
通常我们对缓存有两种操作,存入缓存和更新缓存:
- Cache < K,
- V > cache = ...
-
- public V read(K key) {
- V result = cache.getIfPresent(key);
- if (result == null) {
- result = readFromDatabase(key);
- cache.put(key, result);
- }
-
- return result;
- }
-
- public void write(K key, V value) {
- writeToDatabase(key, value);
- // force the value to be re-read from
- // the database on next read(key) invocation
- cache.invalidate(key);
- };
|
这是一种get-if absent compute-put模式,也就是如果缓存没有该元素,则从数据库获得放入缓存。
假设有两个线程T1和T2,第一个调用缓存读取,第二个缓存写入,两个线程同时运行时,缓存中获取的值可能不是刚刚写入数据库值,也就是脏数据。
使用Guava测试代码如下:
- AtomicReference < Integer > db = new AtomicReference < >(1);
-
- LoadingCache < String,
- Integer > c = CacheBuilder.newBuilder().build(new CacheLoader < String, Integer > () {
- public Integer load(String key) {
- println("Reading from db ...");
- Integer v = db.get();
- sleep(1000L);
- println("Read from db: " + v);
- return v;
- }
- });
-
- Thread t1 = new Thread(() - >{
- Integer g = c.get("k");
- println("Got from cache: " + g);
- });
-
- Thread t2 = new Thread(() - >{
- sleep(500L);
- println("Writing to db ...");
- db.set(2);
- println("Wrote to db");
- c.invalidate("k");
- println("Invalidated cached");
- });
-
- t1.start();
- t2.start();
-
- t1.join();
- t2.join();
-
- System.out.println();
- println("In cache: " + c.get("k"));
|
得到结果:
-
- Thread-1 (123): Reading from db ...
- Thread-2 (612): Writing to db ...
- Thread-2 (612): Wrote to db
- Thread-2 (613): Invalidated cached
- Thread-1 (1142): Read from db: 1
- Thread-1 (1145): Got from cache: 1
-
- main (1146): In cache: 1
|
尽管缓存已经invalidate,但是缓存还是能获得K的值。
而如果使用Caffeine.newBuilder(),能得到正确结果:
-
- Thread-1 (122): Reading from db ...
- Thread-2 (624): Writing to db ...
- Thread-2 (624): Wrote to db
- Thread-1 (1146): Read from db: 1
- Thread-2 (1146): Invalidated cached
- Thread-1 (1146): Got from cache: 1
-
- main (1147): Reading from db ...
- main (2149): Read from db: 2
- main (2149): In cache: 2
|
这获得了正确及俄国,是因为Caffeine 有一个 key-scoped锁,当调用cache.get时,指定键key的锁会一直保留到其值被计算加载完成。
GitHub - ben-manes/caffeine: A high performance ca
来源: http://www.jdon.com/48814