国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - JDK動態代理之WeakCache緩存的實現機制

JDK動態代理之WeakCache緩存的實現機制

2021-04-08 12:17Java教程網 Java教程

這篇文章主要介紹了JDK動態代理之WeakCache緩存的實現機制,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Reference引用隊列
private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
//緩存的底層實現, key為一級緩存, value為二級緩存。 為了支持null, map的key類型設置為Object
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>>
                            map = new ConcurrentHashMap<>();
//reverseMap記錄了所有代理類生成器是否可用, 這是為了實現緩存的過期機制
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;
 
//構造器, 傳入生成二級緩存key的工廠和生成二級緩存value的工廠
public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) {
  this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
  this.valueFactory = Objects.requireNonNull(valueFactory);
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public V get(K key, P parameter) {
  //這里要求實現的接口不能為空
  Objects.requireNonNull(parameter);
  //清除過期的緩存
  expungeStaleEntries();
  //將ClassLoader包裝成CacheKey, 作為一級緩存的key
  Object cacheKey = CacheKey.valueOf(key, refQueue);
  //獲取得到二級緩存
  ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
  //如果根據ClassLoader沒有獲取到對應的值
  if (valuesMap == null) {
    //以CAS方式放入, 如果不存在則放入,否則返回原先的值
    ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey,
        valuesMap = new ConcurrentHashMap<>());
    //如果oldValuesMap有值, 說明放入失敗
    if (oldValuesMap != null) {
      valuesMap = oldValuesMap;
    }
  }
  //根據代理類實現的接口數組來生成二級緩存key, 分為key0, key1, key2, keyx
  Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
  //這里通過subKey獲取到二級緩存的值
  Supplier<V> supplier = valuesMap.get(subKey);
  Factory factory = null;
  //這個循環提供了輪詢機制, 如果條件為假就繼續重試直到條件為真為止
  while (true) {
    //如果通過subKey取出來的值不為空
    if (supplier != null) {
      //在這里supplier可能是一個Factory也可能會是一個CacheValue
      //在這里不作判斷, 而是在Supplier實現類的get方法里面進行驗證
      V value = supplier.get();
      if (value != null) {
        return value;
      }
    }
    if (factory == null) {
      //新建一個Factory實例作為subKey對應的值
      factory = new Factory(key, parameter, subKey, valuesMap);
    }
    if (supplier == null) {
      //到這里表明subKey沒有對應的值, 就將factory作為subKey的值放入
      supplier = valuesMap.putIfAbsent(subKey, factory);
      if (supplier == null) {
        //到這里表明成功將factory放入緩存
        supplier = factory;
      }
      //否則, 可能期間有其他線程修改了值, 那么就不再繼續給subKey賦值, 而是取出來直接用
    } else {
      //期間可能其他線程修改了值, 那么就將原先的值替換
      if (valuesMap.replace(subKey, supplier, factory)) {
        //成功將factory替換成新的值
        supplier = factory;
      } else {
        //替換失敗, 繼續使用原先的值
        supplier = valuesMap.get(subKey);
      }
    }
  }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private final class Factory implements Supplier<V> {
  //一級緩存key, 根據ClassLoader生成
  private final K key;
  //代理類實現的接口數組
  private final P parameter;
  //二級緩存key, 根據接口數組生成
  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讓調用者繼續輪詢重試
      //期間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成功放入二級緩存后, 再對它進行標記
      reverseMap.put(cacheValue, Boolean.TRUE);
    } else {
      throw new AssertionError("Should not reach here");
    }
    //最后返回沒有被弱引用包裝的代理類
    return value;
  }
}

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

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 国内精品视频 | 成人中文字幕在线观看 | 国产日产久久高清欧美一区 | 97碰碰碰免费公开在线视频 | 中文字幕国产在线视频 | 国产精品免费一区二区三区四区 | 无毛av| 久久久九色| 一本综合久久 | 久久丁香 | 曰本人一级毛片免费完整视频 | 91精品久久久久久久久久久久久久久 | 国产在线二区 | 国产精品区一区二区三含羞草 | 一区二区av | 亚洲专区 变态 另类 | 亚洲欧美综合精品久久成人 | 福利片在线 | 99免费视频| 99久久综合精品五月天 | 欧美亚洲国产一区二区三区 | 欧美成人免费 | 一区二区久久 | 九九热精品在线播放 | 云南一级毛片 | 欧美综合区 | 欧美一区二区三区在线 | 中文字幕av第一页 | 久草美女 | 日韩精品一二三 | 91在线视频 | 国产一区二 | 亚洲va国产天堂va久久 en | 国产片在线观看.com | 日韩精品无码一区二区三区 | 成人精品一区二区三区中文字幕 | 日韩大片免费看 | 最近中文字幕免费观看 | 国产精品久久久久久久 | 日韩欧美国产一区二区 | 欧美大片黄 |