Guava Cache与ConcurrentHashMap很相似,区别在于Guava Cache能设置回收,解决了大数据缓存导致的内存溢出问题
Guava Cache的回收方式有三种:基于容量回收、定时回收和基于引用回收
具体介绍参照:http://ifeve.com/google-guava-cachesexplained/
上测试代码:
public class CacheTest { public static void main(String[] args) { for (int i = 0; i < 2; i++) { new Thread(new Runnable() { @Override public void run() { try { testLoadCache("key1", "key2"); } catch (ExecutionException e) { e.printStackTrace(); } } }).start(); } } private static int index = 0; // 这里设置了初始容量为16,缓存有效期1S private static LoadingCache<String, String> lCache = CacheBuilder.newBuilder().initialCapacity(16).expireAfterAccess(1, TimeUnit.SECONDS) .build(new CacheLoader<String, String>() { // 默认的数据加载实现,当调用get取值时,如果key没有对应的值,则调用此方法进行加载。如果get方法指定了Callable则调用call方法来替换 @Override public String load(String key) throws Exception { System.out.println( Thread.currentThread().getName() + " compute , load index================== " + index++); return "load-default"; } }); public static void testLoadCache(String key, String key2) throws ExecutionException { // 创建get中使用的覆盖Callable对象 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { System.out.println( Thread.currentThread().getName() + " compute , call index================== " + index++); return "call-overwrite"; } }; // 获取数据,如果没有key对应的值则调用load加载并返回加载出来的值 String value = lCache.get(key); // 获取数据,如果没有key对应的值则调用Call加载并返回加载出来的值,这里的call覆盖了load加载 String value2 = lCache.get(key2, callable); System.out.println(Thread.currentThread().getName() + "-------------" + value); System.out.println(Thread.currentThread().getName() + "============= " + value2); try { // 睡眠2S用于测试缓存有效期 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("\n*****************************************************\n"); // 缓存中数据已经被回收清理,此处将重新进行加载 value = lCache.get(key); value2 = lCache.get(key2, callable); System.out.println(Thread.currentThread().getName() + "-------------" + value); System.out.println(Thread.currentThread().getName() + "============= " + value2); } }
执行结果
Thread-1 compute , load index================== 0
Thread-1 compute , call index================== 1
Thread-1-------------load-default
Thread-1============= call-overwrite
Thread-2-------------load-default
Thread-2============= call-overwrite
*****************************************************
*****************************************************
Thread-1 compute , load index================== 2
Thread-1 compute , call index================== 3
Thread-1-------------load-default
Thread-1============= call-overwrite
Thread-2-------------load-default
Thread-2============= call-overwrite
Thread-1 compute , call index================== 1
Thread-1-------------load-default
Thread-1============= call-overwrite
Thread-2-------------load-default
Thread-2============= call-overwrite
*****************************************************
*****************************************************
Thread-1 compute , load index================== 2
Thread-1 compute , call index================== 3
Thread-1-------------load-default
Thread-1============= call-overwrite
Thread-2-------------load-default
Thread-2============= call-overwrite
发现超时后缓存被回收,当再使用时又重新进行初始化加载...
可以使用Guava Cache来替换ConcurrentHashMap进行数据缓存,即能满足高并发缓存读写,又解决了缓存过大导致的内存溢出