Guava Cache之Cache接口

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));
	}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章