緩存是提升性能的一把利器。
經常使用到的緩存技術有分佈式緩存,像Redis、MC;也有本地緩存,像ehcache、guava cache等。這裏說的是本地緩存guava cache。java
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)異步