2019独角兽企业重金招聘Python工程师标准>>>
1、通过put或putAll手动向Cache中添加数据,guava不缓存value是null的key。我们可以在系统启动的时候,就将某些数据手动放入缓存中,这样就可以避免系统启动后,第一个用户访问缓存不能命中的情况。
public static void testPut() { Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(3).recordStats().build(); // 通过put或者putAll手动将数据添加到缓存 cache.put("id", "10"); Map<String, String> batch = new HashMap<>(); cache.put("name", "aty"); cache.put("addr", "sz"); cache.putAll(batch); // 数量超出最大限制,会导致guava清除之前的数据,evictionCount增加1 // 手动添加缓存数据,不会影响其他缓存统计指标值 cache.put("new", "replace"); System.out.println(cache.stats()); // 不接受null try { cache.put("a", null); } catch (NullPointerException e) { }
}
2、通过getIfPresent/getAllPresent/get读取缓存中的数据。
public static void testGet() throws Exception { Cache<String, String> cache = CacheBuilder.newBuilder().recordStats().build(); cache.put("name", "aty"); // 缓存未命中missCount加1 System.out.println(cache.getIfPresent("s") == null); System.out.println(cache.stats()); // 缓存命中hitCount加1 System.out.println(cache.getIfPresent("name") != null); System.out.println(cache.stats()); // Callable.call()不能返回null,否则guava报异常 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(2000); return "demo"; } }; // 使用guava Stopwatch计时 Stopwatch watch = Stopwatch.createStarted(); cache.get("a", callable); watch.stop(); // 缓存不存在missCount加1,调用时间也会增加到totalLoadTime System.out.println(cache.stats()); // 大致2s 可以证明: guava cache是在调用者的线程中执行callable任务的 System.out.println("elapse time=" + watch.elapsed(TimeUnit.MILLISECONDS));
}
3、如果明确知道某些缓存无用,我们可以通过invalidate/invalidateAll删除
public static void testDelete() { Cache<String, String> cache = CacheBuilder.newBuilder().recordStats().build(); cache.put("a", "aty"); cache.put("b", "aty"); cache.put("c", "aty"); cache.put("d", "aty"); // 单个删除 cache.invalidate("a"); System.out.println(cache.stats()); System.out.println(cache.size()); // 3 // 批量删除 cache.invalidateAll(Arrays.asList("b", "c")); System.out.println(cache.stats()); System.out.println(cache.size()); // 1 // 清除所有 cache.invalidateAll(); System.out.println(cache.stats()); System.out.println(cache.size()); // 0
}
4、通过调用cleanUp执行缓存清理操作,比如删除过期的key。
public static void testCleanup() throws Exception { Cache<String, String> cache = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS).build(); cache.put("a", "a"); // 睡眠2s让缓存过期 Thread.sleep(2000); System.out.println(cache.size()); // 缓存大小仍然是1,因为调用这个方法不会触发缓存清除 System.out.println(cache.getIfPresent("a") == null);// 调用get/put会触发缓存清除 Cache<String, String> cache2 = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS).build(); cache2.put("a", "a"); // 睡眠2s让缓存过期 Thread.sleep(2000); cache2.cleanUp();// 手动触发缓存清除动作 System.out.println(cache2.size()); // 0
}
5、通过asMap可以拿到Cache底层使用的数据接口,通过这个map也可以添加或删除cache中的数据。通过map获取数据,不会影响缓存统计;通过map添加数据,可能会影响evictionCount。虽然可以对这个map进行迭代,不过有可能会出现获取到值是null的情况。
public static void testAsMap() throws Exception { Cache<String, String> cache = CacheBuilder.newBuilder().build(); cache.put("a", "a"); cache.put("b", "b"); cache.put("c", "c"); // 通过底层map得到iterator,以便后面遍历 Iterator<String> iterator = cache.asMap().keySet().iterator(); // 1.启动一个线程进入睡眠状态 Thread thread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(60 * 60 * 1000); } catch (InterruptedException e) { cache.invalidate("b"); } } }); thread.start(); while (iterator.hasNext()) { String key = iterator.next(); if (key.equals("b")) { thread.interrupt(); // 唤醒睡眠的线程,模拟线程的交替执行 Thread.sleep(100); // 让唤醒的线程执行完(清除缓存数据) } System.out.println("key=" + key + ",value=" + cache.getIfPresent(key)); } }