緩存是提高性能的一把利器。
常用到的緩存技術有分布式緩存,像Redis、MC;也有本地緩存,像ehcache、guava cache等。這里說的是本地緩存guava cache。
guava cache剛開始接觸,這就記錄下來。。
public static void main(String[] args) throws ExecutionException, InterruptedException{ //緩存接口這里是LoadingCache,LoadingCache在緩存項不存在時可以自動加載緩存 LoadingCache<Integer,Student> studentCache //CacheBuilder的構造函數是私有的,只能通過其靜態方法newBuilder()來獲得CacheBuilder的實例 = CacheBuilder.newBuilder() //設置並發級別為8,並發級別是指可以同時寫緩存的線程數 .concurrencyLevel(8) //設置寫緩存后8秒鍾過期 .expireAfterWrite(8, TimeUnit.SECONDS)
//設置寫緩存后1秒鍾刷新
.refreshAfterWrite(1, TimeUnit. SECONDS) //設置緩存容器的初始容量為10 .initialCapacity(10) //設置緩存最大容量為100,超過100之后就會按照LRU最近雖少使用算法來移除緩存項 .maximumSize(100) //設置要統計緩存的命中率 .recordStats() //設置緩存的移除通知 .removalListener(new RemovalListener<Object, Object>() { @Override public void onRemoval(RemovalNotification<Object, Object> notification) { System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause()); } }) //build方法中可以指定CacheLoader,在緩存不存在時通過CacheLoader的實現自動加載緩存 .build( new CacheLoader<Integer, Student>() { @Override public Student load(Integer key) throws Exception { System.out.println("load student " + key); Student student = new Student(); student.setId(key); student.setName("name " + key); return student; } } ); for (int i=0;i<20;i++) { //從緩存中得到數據,由於我們沒有設置過緩存,所以需要通過CacheLoader加載緩存數據 Student student = studentCache.get(1); System.out.println(student); //休眠1秒 TimeUnit.SECONDS.sleep(1); } System.out.println("cache stats:"); //最后打印緩存的命中率等 情況 System.out.println(studentCache.stats().toString()); }
還有另一種方法
package com; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import com.google.common.cache.*; /** * @author 作者 PZhang E-mail:pzhang@rxhui.com * @date 創建時間:2017-2-15 上午9:58:00 * @version 1.0 * @parameter * @return */ public class CacheModel { public Student getStudent(Integer key){ System.out.println("load student " + key); Student student = new Student(); student.setId(key); student.setName("name " + key); return student; } //load Method public void loadCacheA() throws Exception{ LoadingCache<Integer,Student> studentCache= CacheBuilder.newBuilder().concurrencyLevel(8). expireAfterWrite(8, TimeUnit.SECONDS).refreshAfterWrite(1, TimeUnit. SECONDS).initialCapacity(10).maximumSize(100) .recordStats().removalListener(new RemovalListener<Object, Object>() { public void onRemoval(RemovalNotification<Object, Object> notification) { System.out.println(notification.getKey() + " was removed, cause is " + notification);} }).build( new CacheLoader<Integer, Student>() { @Override public Student load(Integer key) throws Exception { return getStudent(key); } } ); for (int i=0;i<20;i++) { Student student = studentCache.get(1); System.out.println(student); TimeUnit.SECONDS.sleep(1); } System.out.println("cache stats:"); System.out.println(studentCache.stats().toString()); } //call back Method public void loadCacheB(final Integer key) throws Exception{ Cache<Integer, Student> cache = CacheBuilder.newBuilder().maximumSize(1000).recordStats().expireAfterWrite(8, TimeUnit.SECONDS).build(); for (int i=0;i<20;i++) { System.out.println(cache.get(key, new Callable<Student>() { public Student call() { return getStudent(key); } })); TimeUnit.SECONDS.sleep(1); } System.out.println("cache stats:"); System.out.println(cache.stats().toString()); } public static void main(String[] args) throws Exception { CacheModel cache = new CacheModel(); cache.loadCacheB(2); } }
guava Cache數據移除:
guava做cache時候數據的移除方式,在guava中數據的移除分為被動移除和主動移除兩種。
被動移除數據的方式,guava默認提供了三種方式:
1.基於大小的移除:看字面意思就知道就是按照緩存的大小來移除,如果即將到達指定的大小,那就會把不常用的鍵值對從cache中移除。
定義的方式一般為 CacheBuilder.maximumSize(long),還有一種一種可以算權重的方法,個人認為實際使用中不太用到。就這個常用的來看有幾個注意點,
其一,這個size指的是cache中的條目數,不是內存大小或是其他;
其二,並不是完全到了指定的size系統才開始移除不常用的數據的,而是接近這個size的時候系統就會開始做移除的動作;
其三,如果一個鍵值對已經從緩存中被移除了,你再次請求訪問的時候,如果cachebuild是使用cacheloader方式的,那依然還是會從cacheloader中再取一次值,如果這樣還沒有,就會拋出異常
2.基於時間的移除:guava提供了兩個基於時間移除的方法
expireAfterAccess(long, TimeUnit) 這個方法是根據某個鍵值對最后一次訪問之后多少時間后移除
expireAfterWrite(long, TimeUnit) 這個方法是根據某個鍵值對被創建或值被替換后多少時間移除
3.基於引用的移除:
這種移除方式主要是基於java的垃圾回收機制,根據鍵或者值的引用關系決定移除
主動移除數據方式,主動移除有三種方法:
1.單獨移除用 Cache.invalidate(key)
2.批量移除用 Cache.invalidateAll(keys)
3.移除所有用 Cache.invalidateAll()
如果需要在移除數據的時候有所動作還可以定義Removal Listener,但是有點需要注意的是默認Removal Listener中的行為是和移除動作同步執行的,如果需要改成異步形式,可以考慮使用RemovalListeners.asynchronous(RemovalListener, Executor)