1

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

package com.example.springboottest.guava_cache;

import com.google.common.base.MoreObjects;

/***************************************

  • @author:Alex Wang

  • @Date:2017/11/18

  • QQ: 532500648

  • QQ群:463962286
    ***************************************/
    public class Employee
    {
    private final String name;
    private final String dept;
    private final String empID;
    private final byte[] data = new byte[1024 * 1024];

    public Employee(String name, String dept, String empID)
    {
    this.name = name;
    this.dept = dept;
    this.empID = empID;
    }

    public String getName()
    {
    return name;
    }

    public String getDept()
    {
    return dept;
    }

    public String getEmpID()
    {
    return empID;
    }

    @Override
    public String toString()
    {
    return MoreObjects.toStringHelper(this)
    .add("Name", this.getName()).add("Department", getDept())
    .add("EmployeeID", this.getEmpID()).toString();
    }

    @Override
    protected void finalize() throws Throwable
    {
    System.out.println("The name " + getName() + " will be GC.");
    }
    }

package com.example.springboottest.guava_cache;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.Weigher;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class _1_CacheLoaderBasicTest {

public static void main(String[] args) throws Exception{

// test1();
// test2();
// test3();
// test4();
test5();
}

/**測試軟引用在緩存中被過期
 * 需要設置堆內存信息
 * -Xms64M -Xmx64M -XX:+PrintGCDetails
 * @throws Exception
 */
private static void test5() throws Exception{
    LoadingCache<String, Employee> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(200, TimeUnit.SECONDS)
            .softValues()//只能對values 做軟引用處理
            .build(createCacheLoader2());
    int i = 0;
    //Employee 內部會有一個1M的數(shù)組蓖墅,所以一個Employee對象 至少占1M空間
    //由于軟引用在內存快不足的時候會被回收 所以這里運行結果 可以創(chuàng)建很多對象 不止64個
    //todo 但是考慮到軟引用的性能影響 一般我們在在緩存中設置size來限制緩存所占內存的總大小 而不是使用軟引用來
    for (; ; )  {
        String key = "Alex" + i;
        cache.put(key, new Employee(key, key, key));

// cache.get(key);
// System.gc();
System.out.println("The Employee [" + (i++) + "] is store into cache.");
TimeUnit.MILLISECONDS.sleep(200);
}
}

//測試弱引用(weakReference) 在緩存中被過期
public static void test4() throws InterruptedException  {
    LoadingCache<String, Employee> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(2, TimeUnit.SECONDS)
            .weakValues()
            .weakKeys()
            .build(createCacheLoader2());
    cache.getUnchecked("Alex");
    cache.getUnchecked("Guava");

    //active method
    //Thread Active design pattern
    System.gc();
    TimeUnit.MILLISECONDS.sleep(100);
    //weak:弱引用 每次gc的時候 都會將其回收混巧, 所以這里從緩存中拿不到數(shù)據(jù)了
    System.out.println(cache.getIfPresent("Alex"));
}

//測試Write的expire模式下的緩存存活情況
private static void test3() throws Exception {
    LoadingCache<String, Employee> cache = CacheBuilder.newBuilder()
            //expireAfterWrite,write:包括寫(write)和更新(update) 不包括讀(read)
            .expireAfterWrite(2, TimeUnit.SECONDS)
            .build(createCacheLoader2());

    cache.getUnchecked("Guava");

    TimeUnit.SECONDS.sleep(1);
    Employee guava = cache.getIfPresent("Guava");
    System.out.println(guava);//1s后guava 此時存活
    TimeUnit.MILLISECONDS.sleep(900);
    guava = cache.getIfPresent("Guava");
    System.out.println(guava);//1.90s guava 此時依然存活

    TimeUnit.SECONDS.sleep(1);
    guava = cache.getIfPresent("Guava");
    System.out.println(guava);//2.99s guava 此時不存活
}

//測試Access的expire模式下的緩存存活情況
private static void test2() throws Exception{
    LoadingCache<String, Employee> cache = CacheBuilder.newBuilder()
            //expireAfterAccess,access:包括讀(read),寫(write),改(update),都會續(xù)長緩存的存活期
            .expireAfterAccess(2, TimeUnit.SECONDS)
            .build(createCacheLoader2());
    cache.getUnchecked("Alex");

    TimeUnit.SECONDS.sleep(3);
    Employee alex =  cache.getIfPresent("Alex");//睡眠了 3s 此時緩存獲取不到數(shù)據(jù)
    System.out.println(alex);

    cache.getUnchecked("Guava");

    TimeUnit.SECONDS.sleep(1);
    Employee employee = cache.getIfPresent("Guava");//此時Guava存在
    System.out.println(employee);

    TimeUnit.SECONDS.sleep(1);
    employee = cache.getIfPresent("Guava");//再次獲取Guava 依然存在
    System.out.println(employee);

    TimeUnit.SECONDS.sleep(1);
    employee = cache.getIfPresent("Guava");//再次獲取Guava 依然存在
    System.out.println(employee);
}

//測試基礎用法
public static void test1() throws ExecutionException, InterruptedException {
    //創(chuàng)建一個緩存容器對象 其最大容量是3,容器內元素存放30ms就過期
    LoadingCache<String, Employee> cache = CacheBuilder.newBuilder()
            .maximumSize(3)
            .expireAfterAccess(30, TimeUnit.MILLISECONDS)
            .build(createCacheLoader());
    //#################################### 測試30ms時間過期 ####################################

// System.out.println(cache.get("Alex").getName());
// TimeUnit.MILLISECONDS.sleep(31);
// System.out.println(cache.get("Alex").getName());
//測試到達容量之后 LRU過期
//#################################### 測試到達size之后被LRU過期(過期策略:size) ####################################
// System.out.println(cache.get("Alex").getName());
// System.out.println(cache.get("allen").getName());
// System.out.println(cache.get("tom").getName());
// System.out.println(cache.get("amy").getName());//此時Alex被過期調,再拿Alex的話會從DB中拿
// System.out.println(cache.size());
// System.out.println(cache.get("Alex").getName());
// System.out.println();
//#################################### 測試到達weight之后被LRU過期(過期策略:自定義) ####################################

    //設置一個稱重器 稱重的方式是:對象的重量weight = name的長度 + empId的長度 + Dept的長度
    Weigher<String, Employee> weigher = (key, employee) ->
            employee.getName().length() + employee.getEmpID().length() + employee.getDept().length();

    //設置緩存重量限制為45
    LoadingCache<String, Employee> cache2 = CacheBuilder.newBuilder()
            .maximumWeight(45)
            .concurrencyLevel(1)
            .weigher(weigher)
            .build(createCacheLoader());

    cache2.get("Gavin");//緩存重量:15
    cache2.get("Kevin");//緩存重量:30
    cache2.get("Allen");//緩存重量:45
    cache2.get("Jason");//重量已經(jīng)達到45氮帐,此時Gavin被過期

    Employee employee = cache2.getIfPresent("Gavin");//此時再去緩存中拿Gavin 是拿不到的
    System.out.println(employee);


    //#################################### LoadingCache 的一些api ####################################

// 從LoadingCache中拿數(shù)據(jù)谨胞,如果拿不到,會去從DB中拿蹈矮,
// cache.get("aa");
// 與get()方法的區(qū)別是這里不需要顯式捕獲異常
// cache.getUnchecked("aa");
// 從緩存中拿key對應的數(shù)據(jù)砰逻,如果緩存中沒有 就返回null,不會去從DB中拿
// cache.getIfPresent("aa");

}


private static  CacheLoader<String, Employee> createCacheLoader() {
    return new CacheLoader<String, Employee>() {
        @Override
        public Employee load(String key) throws Exception {

// 這里要注意:load的時候不能返回空泛鸟, 那返回空了怎么辦蝠咆?很有可能命中不了
// if (key.equals("aa")) return null;
System.out.println("從數(shù)據(jù)庫中拿數(shù)據(jù): " + key);
return new Employee(key, key, key);
}
};
}

private static CacheLoader<String, Employee> createCacheLoader2()  {
    //也可以使用from()來構建緩存
    return CacheLoader.from(key -> new Employee(key, key, key));
}

}

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市北滥,隨后出現(xiàn)的幾起案子刚操,更是在濱河造成了極大的恐慌,老刑警劉巖再芋,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菊霜,死亡現(xiàn)場離奇詭異,居然都是意外死亡济赎,警方通過查閱死者的電腦和手機鉴逞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門记某,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人构捡,你說我怎么就攤上這事液南。” “怎么了勾徽?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵滑凉,是天一觀的道長。 經(jīng)常有香客問我喘帚,道長畅姊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任吹由,我火速辦了婚禮若未,結果婚禮上,老公的妹妹穿的比我還像新娘溉知。我一直安慰自己陨瘩,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布级乍。 她就那樣靜靜地躺著舌劳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玫荣。 梳的紋絲不亂的頭發(fā)上甚淡,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音捅厂,去河邊找鬼贯卦。 笑死,一個胖子當著我的面吹牛焙贷,可吹牛的內容都是我干的撵割。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼辙芍,長吁一口氣:“原來是場噩夢啊……” “哼啡彬!你這毒婦竟也來了?” 一聲冷哼從身側響起故硅,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤庶灿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吃衅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體往踢,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年徘层,在試婚紗的時候發(fā)現(xiàn)自己被綠了峻呕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片利职。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖山上,靈堂內的尸體忽然破棺而出眼耀,到底是詐尸還是另有隱情,我是刑警寧澤佩憾,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站干花,受9級特大地震影響妄帘,放射性物質發(fā)生泄漏。R本人自食惡果不足惜池凄,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一抡驼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肿仑,春花似錦致盟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伟端,卻和暖如春杯道,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背责蝠。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工党巾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霜医。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓齿拂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肴敛。 傳聞我的和親對象是個殘疾皇子署海,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容

  • 單例定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點值朋。餓漢模式public class Singleto...
    小楊不想努力了閱讀 359評論 0 4
  • Thread類相關狀態(tài)和方法示意圖: 一. Thread類核心API使用 1. 進程是一次程序的執(zhí)行叹侄,可以理解成W...
    有奶喝先森閱讀 925評論 0 15
  • Java8張圖 11、字符串不變性 12昨登、equals()方法趾代、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,696評論 0 11
  • 1 2 命名規(guī)則 標識符起名:不能以數(shù)字開頭丰辣,不能是java的關鍵字撒强,區(qū)分大小寫 標識符組成規(guī)則:英文大小寫禽捆,數(shù)字...
    西瓜菠蘿8800閱讀 223評論 0 0
  • 1.下列Java常見事件類中哪個是鼠標事件類?() A:InputEvent B:KeyEvent C:Mouse...
    哎呀有魚閱讀 748評論 0 1