构建Caffeine 是通过LoadingCache完成的,什么是LoadingCache ?可以调用时候加载的 实现。
build buildAsync
一个是同步,一个异步。
build 返回的是 LoadingCache, 可以直接当作cache 用。
buildAsync 返回的是 AsyncLoadingCache, 其cacheAsync.get(key);方法返回的是CompletableFuture, 然后是 future.get(); 这样的调用呢, 也有一定的阻塞。 一般可能通过监听器的方式调用,这样就没有阻塞。
比如
future.thenApply()
future.thenAcceptAsync()
...
getIfPresent 方法呢,直接返回cache已经存在的,就是说不会另外去加载,去load。 他和get 方法是对立的。
private static void testCaffine() { /* 同步 */ LoadingCache<String, DataObject> cache = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) .build(k -> DataObject.get("Data for " + k)); String k1 = "key1"; // 1 第一次get key1,因为之前没有加载过,那么就会触发第一次加载,也就是执行build的参数的 lamda函数,然后存放到cache里面去。 // 这个加载是 临时的、实时的、同步的。 // System.out.println("cache = " + cache.get(k1).getData()); // 2 cache的get方法 还可以传入一个lamda函数,用来进行加载, 会覆盖build方法参数的lamda函数。但是,如果之前已经加载,那么这里的get 的lamda函数 将不会执行,而是直接返回存储的值。 DataObject dataObject; dataObject = cache .get("testKey1", k -> DataObject.get("overrided for " + k)); System.out.println("dataObject = " + dataObject.getData()); dataObject = cache .get("testKey1", k -> DataObject.get("overrided new for Aaa"));// 这里就不会执行 System.out.println("dataObject = " + dataObject.getData()); String k2 = "key2"; // 3 第一次get key1,因为之前没有加载过,且getIfPresent 仅仅在key 存在的时候返回对应value,不存在则null, 它不会进行 加载即执行build 进行load;所以是返回null DataObject ifPresent = cache.getIfPresent(k2); System.out.println("ifPresent = " + ifPresent); DataObject dataObject2 = cache.get(k2); System.out.println("dataObject = " + dataObject2.getData()); // 前面已经执行过一次get方法,所以这一回getIfPresent 可以正确返回,而不是null ifPresent = cache.getIfPresent(k2); System.out.println("ifPresent = " + ifPresent); // Iterable<? extends DataObject> ks = (t) -> { // System.out.println("" + t); // return new DataOb; // }; ConcurrentMap<String, DataObject> stringDataObjectConcurrentMap = cache.asMap(); System.out.println("stringDataObjectConcurrentMap = " + stringDataObjectConcurrentMap); DataObject dataObject1 = cache.get(k1, s -> new DataObject(s + "aaaaaaa ")); dataObject1 = cache.get("key3", s -> new DataObject(s + "aaaaaaa ")); System.out.println("dataObject1 = " + dataObject1); // getAll 方法需要的是一个key 的list的iterator! 为什么getAll 必须有参数? 为什么没有getAllKeys方法,大概是没有什么必要。 Iterable<String> aNew = ArrayListIterator::new;// 通过这样的方式给getAll 是没有用的, 因为里面是空的,根本没有key Map<String, DataObject> all = cache.getAll(() -> {ArrayList arrayList = new ArrayList();arrayList.add(k2);arrayList.add(k1);return arrayList.iterator();}); Set<Map.Entry<String, DataObject>> entries = all.entrySet(); for (Iterator<Map.Entry<String, DataObject>> iterator = entries.iterator(); iterator.hasNext(); ) { Map.Entry<String, DataObject> next = iterator.next(); System.out.println(next.getKey() + " next = " + next.getValue()); } /* 异步 */ AsyncLoadingCache<Object, DataObject> cache2 = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) .buildAsync(k -> DataObject.get("Data for " + k)); CompletableFuture<DataObject> future = cache2.get(k1); DataObject o = null; try { o = future.get(); System.out.println("cache = " + o.getData()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
其中DataObject
class DataObject { private final String data; private static int objectCounter = 0; // standard constructors/getters public DataObject(String data) { this.data = data; } public String getData() { return data; } public static int getObjectCounter() { return objectCounter; } public static void setObjectCounter(int objectCounter) { DataObject.objectCounter = objectCounter; } public static DataObject get(String data) { objectCounter++; return new DataObject(data); } @Override public String toString() { return "DataObject{" + "data='" + data + '\'' + "objectCounter='" + objectCounter + '\'' + '}'; } }
总结
参考
https://www.cnblogs.com/eyougo/p/15032900.html