这里我们主要介绍LoadingCache,对于LoadingCache主要有:
它本身继承自AbstractMap,实现了ConcurrentMap。是根据jdk1.7中的ConcurrentHashMap中的分段锁的原理来实现的,构造方法为:
先分N个Segment加锁,Segment下面才是HashMap。这样就把原本一个锁,打散成N个锁。但和ConcurrentHashMap默认16个锁不一样,GuavaCache默认是4个锁。下面的concurrencyLevel是根据这个来设置的。
1. Cache<Object, Object> realTimeCache = CacheBuilder.newBuilder().maximumSize(2000).maximumWeight(2000). //并发级别,即锁粒度 .concurrencyLevel(16). expireAfterWrite(7, TimeUnit.DAYS).build();
2. CacheBuilder.newBuilder() .expireAfterWrite(time, TimeUnit.MINUTES) .build(new CacheLoader<Long, Object>() { @Override public Object load(Long key) throws Exception { return new Object(); } });
缓存控制主要有根据大小和时间还有缓存引用这几种方式。根据大小:
V getOrLoad(K key) throws ExecutionException { return get(key, defaultLoader); }
V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException { int hash = hash(checkNotNull(key)); return segmentFor(hash).get(key, hash, loader); }
创建新段的时候是通过loadSync去加载的:
实际加载的过程为:
可以看到在com.google.common.cache.LocalCache.Segment#loadSync和com.google.common.cache.LocalCache.Segment#loadAsync方法中都有ListenableFutureloadingFuture = loadingValueReference.loadFuture(key, loader)的操作, 在其内部调用的是com.google.common.cache.CacheLoader#reload方法,使用的是Futures.immediateFuture(load(key))阻塞式的返回方法。如果load的过程比较耗时,会造成卡顿,需要设置后台刷新。
public static <K, V> CacheLoader<K, V> asyncReloading( final CacheLoader<K, V> loader, final Executor executor)
可以传入一个Executor。
上述两种方法哪种更好,一般建议使用后一种,因为前一种包装类的方式可能会不内联。
参考江南白衣的博客:http://calvin1978.blogcn.com/articles/guava-cache%E5%B0%8F%E8%AE%B0.html