Guava Cache 与 ConcurrentMap 很相似,但也不完全一样。最基本的区别是:ConcurrentMap 会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache 为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管 LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。Guava Cache 是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效。

■ 本地缓存的应用场景: 对性能有非常高的要求 不经常变化 占用内存不大 有访问整个集合的需求 数据允许不时时一致

■ Guava Cache 的优势 缓存过期和淘汰机制 在GuavaCache中可以设置Key的过期时间,包括访问过期和创建过期 GuavaCache在缓存容量达到指定大小时,采用LRU的方式,将不常使用的键值从Cache中删除 并发处理能力 GuavaCache类似CurrentHashMap,是线程安全的。 提供了设置并发级别的api,使得缓存支持并发的写入和读取 采用分离锁机制,分离锁能够减小锁力度,提升并发能力 分离锁是分拆锁定,把一个集合看分成若干partition, 每个partiton一把锁。ConcurrentHashMap就是分了16个区域,这16个区域之间是可以并发的。GuavaCache采用Segment做分区。 更新锁定 一般情况下,在缓存中查询某个key,如果不存在,则查源数据,并回填缓存。(Cache Aside Pattern)在高并发下会出现,多次查源并重复回填缓存,可能会造成源的宕机(DB),性能下降 GuavaCache可以在CacheLoader的load方法中加以控制,对同一个key,只让一个请求去读源并回填缓存,其他请求阻塞等待。 集成数据源 一般我们在业务中操作缓存,都会操作缓存和数据源两部分GuavaCache的get可以集成数据源,在从缓存中读取不到时可以从数据源中读取数据并回填缓存 监控缓存加载/命中情况 统计

接口Cache代表一块缓存,它有如下方法

public interface Cache<K, V> {
    V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
    ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
    void put(K key, V value);
    void putAll(Map<? extends K, ? extends V> m);
    void invalidate(Object key);
    void invalidateAll(Iterable<?> keys);
    void invalidateAll();
    long size();
    CacheStats stats();
    ConcurrentMap<K, V> asMap();
    void cleanUp();
}

使用实例

GuavaCache有两种创建方式: CacheLoader和Callable callback

public class GuavaDemo {
    public static void main(String args[]) throws Exception {
        LoadingCache<String, Object> cache = CacheBuilder.newBuilder()
                // 最大3个 //Cache中存储的对象,写入3秒后过期
                .maximumSize(3).expireAfterWrite(3,
                        //记录命中率 失效通知
                        TimeUnit.SECONDS).recordStats().removalListener(new
                        RemovalListener<Object, Object>() {
                            public void onRemoval(RemovalNotification<Object, Object>
                                                          notification) {
                                System.out.println(notification.getKey() + ":" + notification.getCause());
                            }
                        }.build(
                                new CacheLoader<String, Object>() {
                                    @Override
                                    public String load(String s) throws Exception {
                                        return Constants.hm.get(s);
                                    }
                                }
                        );
        /*
        初始化cache
        */
        initCache(cache);
        System.out.println(cache.size());
        displayCache(cache);
        System.out.println("=============================");
        Thread.sleep(1000);
        System.out.println(cache.getIfPresent("1"));
        Thread.sleep(2500);
        System.out.println("=============================");
        displayCache(cache);
    }

    public static Object get(String key, LoadingCache cache) throws Exception {
        Object value = cache.get(key, new Callable() {
            @Override
            public Object call() throws Exception {
                Object v = Constants.hm.get(key);
                //设置回缓存
                cache.put(key, v);
                return v;
            }
        });
        return value;
    }

    public static void initCache(LoadingCache cache) throws Exception {
        /*
        前三条记录
        */
        for (int i = 1; i <= 3; i++) {
            cache.get(String.valueOf(i));
        }
    } 
    /**
     *获得当前缓存的记录
    @param
    cache
    *@throws Exception
    **/

    public static void displayCache(LoadingCache cache) throws Exception {
        Iterator its = cache.asMap().entrySet().iterator();
        while (its.hasNext()) {
            System.out.println(its.next().toString());
        }
    }

    
}

## CacheLoader
LoadingCache<String,String> cache = CacheBuilder.newBuilder()
	.maximumSize(3)
	.build(
		new CacheLoader<String, String>() {
			@Override
			public String load(String s) throws Exception {
			return Constants.hm.get(s);
			}
		}
	);
## Callable Callback
public static Object get(String key,LoadingCache cache)throws Exception{
	Object value=cache.get(key, new Callable() {
		@Override
		public Object call() throws Exception {
			String v= Constants.hm.get(key);
			//设置回缓存
			cache.put(key,v);
			return v;
		}
	});
	return value;
}


■ GuavaCache的数据删除分为:被动删除和主动删除

//基于数据大小的删除
LoadingCache<String,Object> cache= CacheBuilder.newBuilder()
	/*
	加附加的功能
	*/
	//最大个数
	.maximumSize(3)
	.build(new CacheLoader<String, Object>() {
		//读取数据源
		@Override
		public Object load(String key) throws Exception {
			return Constants.hm.get(key);
		}
	});
	//读取缓存中的1的数据 缓存有就读取 没有就返回null
	System.out.println(cache.getIfPresent("5"));
	//读取4 读源并回写缓存 淘汰一个(LRU+FIFO)
	get("4",cache);
//缓存中的数据 如果3秒内没有访问则删除
.maximumSize(3).expireAfterAccess(3, TimeUnit.SECONDS)
。。。。
Thread.sleep(1000);
//访问1 1被访问
cache.getIfPresent("1");
//歇了2.1秒
Thread.sleep(2100);
//最后缓存中会留下1
System.out.println("==================================");
display(cache);


//基于引用的删除
LoadingCache<String,Object> cache = CacheBuilder.newBuilder()
// 最大3个 值的弱引用
.maximumSize(3).weakValues()
.build();
Object value = new Object();
cache.put("1",value);
value = new Object();//原对象不再有强引用
//强制垃圾回收
System.gc();
System.out.println(cache.getIfPresent("1"));

////将key=1 删除
cache.invalidate("1");
//将key=1和2的删除
cache.invalidateAll(Arrays.asList("1","2"));
//清空缓存
cache.invalidateAll();


查看文档 http://www.ibloger.net/article/3345.html