最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JDK動態(tài)代理之WeakCache緩存的實現(xiàn)機制

 更新時間:2018年02月27日 15:01:56   投稿:lijiao  
這篇文章主要介紹了JDK動態(tài)代理之WeakCache緩存的實現(xiàn)機制

上一篇我們分析了Proxy類的內(nèi)部是怎樣產(chǎn)生代理類的,我們看到了Proxy內(nèi)部用到了緩存機制,如果根據(jù)提供的類加載器和接口數(shù)組能在緩存中找到代理類就直接返回該代理類,否則會調(diào)用ProxyClassFactory工廠去生成代理類。這里用到的緩存是二級緩存,它的一級緩存key是根據(jù)類加載器生成的,二級緩存key是根據(jù)接口數(shù)組生成的。具體的內(nèi)部機制我們直接貼上代碼詳細(xì)解釋。

//Reference引用隊列
private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
//緩存的底層實現(xiàn), key為一級緩存, value為二級緩存。 為了支持null, map的key類型設(shè)置為Object
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> 
                            map = new ConcurrentHashMap<>();
//reverseMap記錄了所有代理類生成器是否可用, 這是為了實現(xiàn)緩存的過期機制
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();
//生成二級緩存key的工廠, 這里傳入的是KeyFactory
private final BiFunction<K, P, ?> subKeyFactory;
//生成二級緩存value的工廠, 這里傳入的是ProxyClassFactory
private final BiFunction<K, P, V> valueFactory;

//構(gòu)造器, 傳入生成二級緩存key的工廠和生成二級緩存value的工廠
public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) {
  this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
  this.valueFactory = Objects.requireNonNull(valueFactory);
}

首先我們看一下WeakCache的成員變量和構(gòu)造器,WeakCache緩存的內(nèi)部實現(xiàn)是通過ConcurrentMap來完成的,成員變量map就是二級緩存的底層實現(xiàn),reverseMap是為了實現(xiàn)緩存的過期機制,subKeyFactory是二級緩存key的生成工廠,通過構(gòu)造器傳入,這里傳入的值是Proxy類的KeyFactory,valueFactory是二級緩存value的生成工廠,通過構(gòu)造器傳入,這里傳入的是Proxy類的ProxyClassFactory。接下來我們看一下WeakCache的get方法。

public V get(K key, P parameter) {
  //這里要求實現(xiàn)的接口不能為空
  Objects.requireNonNull(parameter);
  //清除過期的緩存
  expungeStaleEntries();
  //將ClassLoader包裝成CacheKey, 作為一級緩存的key
  Object cacheKey = CacheKey.valueOf(key, refQueue);
  //獲取得到二級緩存
  ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  //如果根據(jù)ClassLoader沒有獲取到對應(yīng)的值
  if (valuesMap == null) {
    //以CAS方式放入, 如果不存在則放入,否則返回原先的值
    ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, 
        valuesMap = new ConcurrentHashMap<>());
    //如果oldValuesMap有值, 說明放入失敗
    if (oldValuesMap != null) {
      valuesMap = oldValuesMap;
    }
  }
  //根據(jù)代理類實現(xiàn)的接口數(shù)組來生成二級緩存key, 分為key0, key1, key2, keyx
  Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  //這里通過subKey獲取到二級緩存的值
  Supplier<V> supplier = valuesMap.get(subKey);
  Factory factory = null;
  //這個循環(huán)提供了輪詢機制, 如果條件為假就繼續(xù)重試直到條件為真為止
  while (true) {
    //如果通過subKey取出來的值不為空
    if (supplier != null) {
      //在這里supplier可能是一個Factory也可能會是一個CacheValue
      //在這里不作判斷, 而是在Supplier實現(xiàn)類的get方法里面進行驗證
      V value = supplier.get();
      if (value != null) {
        return value;
      }
    }
    if (factory == null) {
      //新建一個Factory實例作為subKey對應(yīng)的值
      factory = new Factory(key, parameter, subKey, valuesMap);
    }
    if (supplier == null) {
      //到這里表明subKey沒有對應(yīng)的值, 就將factory作為subKey的值放入
      supplier = valuesMap.putIfAbsent(subKey, factory);
      if (supplier == null) {
        //到這里表明成功將factory放入緩存
        supplier = factory;
      }
      //否則, 可能期間有其他線程修改了值, 那么就不再繼續(xù)給subKey賦值, 而是取出來直接用
    } else {
      //期間可能其他線程修改了值, 那么就將原先的值替換
      if (valuesMap.replace(subKey, supplier, factory)) {
        //成功將factory替換成新的值
        supplier = factory;
      } else {
        //替換失敗, 繼續(xù)使用原先的值
        supplier = valuesMap.get(subKey);
      }
    }
  }
}

WeakCache的get方法并沒有用鎖進行同步,那它是怎樣實現(xiàn)線程安全的呢?因為它的所有會進行修改的成員變量都使用了ConcurrentMap,這個類是線程安全的。因此它將自身的線程安全委托給了ConcurrentMap, get方法盡可能的將同步代碼塊縮小,這樣可以有效提高WeakCache的性能。我們看到ClassLoader作為了一級緩存的key,這樣可以首先根據(jù)ClassLoader篩選一遍,因為不同ClassLoader加載的類是不同的。然后它用接口數(shù)組來生成二級緩存的key,這里它進行了一些優(yōu)化,因為大部分類都是實現(xiàn)了一個或兩個接口,所以二級緩存key分為key0,key1,key2,keyX。key0到key2分別表示實現(xiàn)了0到2個接口,keyX表示實現(xiàn)了3個或以上的接口,事實上大部分都只會用到key1和key2。這些key的生成工廠是在Proxy類中,通過WeakCache的構(gòu)造器將key工廠傳入。這里的二級緩存的值是一個Factory實例,最終代理類的值是通過Factory這個工廠來獲得的。

private final class Factory implements Supplier<V> {
  //一級緩存key, 根據(jù)ClassLoader生成
  private final K key;
  //代理類實現(xiàn)的接口數(shù)組
  private final P parameter;
  //二級緩存key, 根據(jù)接口數(shù)組生成
  private final Object subKey;
  //二級緩存
  private final ConcurrentMap<Object, Supplier<V>> valuesMap;

  Factory(K key, P parameter, Object subKey,
      ConcurrentMap<Object, Supplier<V>> valuesMap) {
    this.key = key;
    this.parameter = parameter;
    this.subKey = subKey;
    this.valuesMap = valuesMap;
  }

  @Override
  public synchronized V get() {
    //這里再一次去二級緩存里面獲取Supplier, 用來驗證是否是Factory本身
    Supplier<V> supplier = valuesMap.get(subKey);
    if (supplier != this) {
      //在這里驗證supplier是否是Factory實例本身, 如果不則返回null讓調(diào)用者繼續(xù)輪詢重試
      //期間supplier可能替換成了CacheValue, 或者由于生成代理類失敗被從二級緩存中移除了
      return null;
    }
    V value = null;
    try {
      //委托valueFactory去生成代理類, 這里會通過傳入的ProxyClassFactory去生成代理類
      value = Objects.requireNonNull(valueFactory.apply(key, parameter));
    } finally {
      //如果生成代理類失敗, 就將這個二級緩存刪除
      if (value == null) {
        valuesMap.remove(subKey, this);
      }
    }
    //只有value的值不為空才能到達這里
    assert value != null;
    //使用弱引用包裝生成的代理類
    CacheValue<V> cacheValue = new CacheValue<>(value);
    //將包裝后的cacheValue放入二級緩存中, 這個操作必須成功, 否則就報錯
    if (valuesMap.replace(subKey, this, cacheValue)) {
      //將cacheValue成功放入二級緩存后, 再對它進行標(biāo)記
      reverseMap.put(cacheValue, Boolean.TRUE);
    } else {
      throw new AssertionError("Should not reach here");
    }
    //最后返回沒有被弱引用包裝的代理類
    return value;
  }
}

我們再看看Factory這個內(nèi)部工廠類,可以看到它的get方法是使用synchronized關(guān)鍵字進行了同步。進行g(shù)et方法后首先會去驗證subKey對應(yīng)的suppiler是否是工廠本身,如果不是就返回null,而WeakCache的get方法會繼續(xù)進行重試。如果確實是工廠本身,那么就會委托ProxyClassFactory生成代理類,ProxyClassFactory是在構(gòu)造WeakCache的時候傳入的。所以這里解釋了為什么最后會調(diào)用到Proxy的ProxyClassFactory這個內(nèi)部工廠來生成代理類。生成代理類后使用弱引用進行包裝并放入reverseMap中,最后會返回原裝的代理類。

至此已經(jīng)為大家詳細(xì)揭示了WeakCache緩存的實現(xiàn)包括它的一級緩存和二級緩存實現(xiàn)的原理,以及二級緩存key生成的原理,還有最后它是怎樣調(diào)用ProxyClassFactory來生成代理類的。在下一篇中將會深入ProxyGenerator這個類,來看看具體的代理類的字節(jié)碼生成過程。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 說一說java關(guān)鍵字final和transient

    說一說java關(guān)鍵字final和transient

    這篇文章主要和大家說一說java關(guān)鍵字final和transient,感興趣的小伙伴們可以參考一下
    2016-06-06
  • springboot整合jquery和bootstrap框架過程圖解

    springboot整合jquery和bootstrap框架過程圖解

    這篇文章主要介紹了springboot整合jquery和bootstrap框架過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • Java web三件套listener、filter、servelt原理解析

    Java web三件套listener、filter、servelt原理解析

    這篇文章主要介紹了Java web三件套listener、filter、servelt原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Spring Boot使用Druid和監(jiān)控配置方法

    Spring Boot使用Druid和監(jiān)控配置方法

    Druid是Java語言中最好的數(shù)據(jù)庫連接池,并且能夠提供強大的監(jiān)控和擴展功能。下面來說明如何在 Spring Boot 中配置使用Druid
    2017-04-04
  • Java集合教程之Collection實例詳解

    Java集合教程之Collection實例詳解

    集合,或者叫容器,是一個包含多個元素的對象,下面這篇文章主要給大家介紹了關(guān)于Java集合教程之Collection的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • intellij idea隱藏.iml和.idea等自動生成文件的問題

    intellij idea隱藏.iml和.idea等自動生成文件的問題

    這篇文章主要介紹了intellij idea隱藏.iml和.idea等自動生成文件的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • SpringMVC+Mybatis實現(xiàn)的Mysql分頁數(shù)據(jù)查詢的示例

    SpringMVC+Mybatis實現(xiàn)的Mysql分頁數(shù)據(jù)查詢的示例

    本篇文章主要介紹了SpringMVC+Mybatis實現(xiàn)的Mysql分頁數(shù)據(jù)查詢的示例,具有一定的參考價值,有興趣的可以了解一下
    2017-08-08
  • Springboot ApplicationRunner的使用解讀

    Springboot ApplicationRunner的使用解讀

    這篇文章主要介紹了Springboot ApplicationRunner的使用解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • springboot+jwt實現(xiàn)token登陸權(quán)限認(rèn)證的實現(xiàn)

    springboot+jwt實現(xiàn)token登陸權(quán)限認(rèn)證的實現(xiàn)

    這篇文章主要介紹了springboot+jwt實現(xiàn)token登陸權(quán)限認(rèn)證的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • SpringBoot項目報錯:"Error?starting?ApplicationContext...."解決辦法

    SpringBoot項目報錯:"Error?starting?ApplicationContext....

    這篇文章主要給大家介紹了關(guān)于SpringBoot項目報錯:“Error?starting?ApplicationContext.?To?display?the?conditions?report?re-run?...”的解決辦法,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08

最新評論

巴楚县| 交口县| 随州市| 安庆市| 二连浩特市| 汉沽区| 凉城县| 上栗县| 开平市| 新邵县| 潮州市| 雷山县| 藁城市| 大名县| 景宁| 丹阳市| 永泰县| 义乌市| 江都市| 巴林右旗| 德惠市| 涞源县| 韩城市| 泸定县| 曲阜市| 犍为县| 甘洛县| 台前县| 宁都县| 正定县| 曲靖市| 罗山县| 杨浦区| 东方市| 迭部县| 偃师市| 陆良县| 白沙| 宁波市| 姚安县| 青冈县|