<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Loading

      強引用、軟引用、弱引用、虛引用及ReferenceQueue的使用

      何為ReferenceQueue

      在java的引用體系中,存在著強引用,軟引用,虛引用,幽靈引用,這4種引用類型。在正常的使用過程中,我們定義的類型都是強引用的,這種引用類型在回收中,只有當其它對象沒有對這個對象的引用時,才會被GC回收掉。簡單來說,對于以下定義:

      Object obj = new Object();
      Ref ref = new Ref(obj);
      

      在這種情況下,如果ref沒有被GC,那么obj這個對象肯定不會GC的。因為ref引用到了obj。如果obj是一個大對象呢,多個這種對象的話,應用肯定一會就掛掉了。

      那么,如果我們希望在這個體系中,如果obj沒有被其它對象引用,只是在這個Ref中存在引用時,就把obj對象gc掉。這時候就可以使用這里提到的Reference對象了。

      我們希望當一個對象被gc掉的時候通知用戶線程,進行額外的處理時,就需要使用引用隊列了。ReferenceQueue即這樣的一個對象,當一個obj被gc掉之后,其相應的包裝類,即ref對象會被放入queue中。我們可以從queue中獲取到相應的對象信息,同時進行額外的處理。比如反向操作,數據清理等。

      使用隊列進行數據監控

      一個簡單的例子,通過往map中放入10000個對象,每個對象大小為1M字節數組。使用引用隊列監控被放入的key的回收情況。代碼如下所示:

      Object value = new Object();
      Map<Object, Object> map = new HashMap<>();
      for(int i = 0;i < 10000;i++) {
          byte[] bytes = new byte[_1M];
          WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, referenceQueue);
          map.put(weakReference, value);
      }
      System.out.println("map.size->" + map.size());
      

      這里使用了weakReference對象,即當值不再被引用時,相應的數據被回收。另外使用一個線程不斷地從隊列中獲取被gc的數據,代碼如下:

      Thread thread = new Thread(() -> {
          try {
              int cnt = 0;
              WeakReference<byte[]> k;
              while((k = (WeakReference) referenceQueue.remove()) != null) {
                  System.out.println((cnt++) + "回收了:" + k);
              }
          } catch(InterruptedException e) {
              //結束循環
          }
      });
      thread.setDaemon(true);
      thread.start();
      

      結果如下所示:

      9992回收了:java.lang.ref.WeakReference@1d13cd4
      9993回收了:java.lang.ref.WeakReference@118b73a
      9994回收了:java.lang.ref.WeakReference@1865933
      9995回收了:java.lang.ref.WeakReference@ad82c
      map.size->10000
      

      在這次處理中,map并沒有因為不斷加入的1M對象由產生OOM異常,并且最終運行結果之后map中的確有1萬個對象。表示確實被放入了相應的對象信息。不過其中的key(即weakReference)對象中的byte[]對象卻被回收了。即不斷new出來的1M數組被gc掉了。

      從命令行中,我們看到有9995個對象被gc,即意味著在map的key中,除了weakReference之外,沒有我們想要的業務對象。那么在這樣的情況下,是否意味著這9995個entry,我們認為就是沒有任何意義的對象,那么是否可以將其移除掉呢。同時還期望size值可以打印出5,而不是10000.
      WeakHashMap就是這樣的一個類似實現。

      在類weakHashMap中的使用

      weakHashMap即使用weakReference當作key來進行數據的存儲,當key中的引用被gc掉之后,它會自動(類似自動)的方式將相應的entry給移除掉,即我們會看到size發生了變化。

      從簡單來看,我們認為其中所有一個類似的機制從queue中獲取引用信息,從而使得被gc掉的key值所對應的entry從map中被移除。這個處理點就在我們調用weakhashmap的各個處理點中,比如get,size,put等。簡單點來說,就是在調用get時,weakHashMap會先處理被gc掉的key值,然后再處理我們的業務調用。

      簡單點代碼如下:

      public int size() {
          if (size == 0)
              return 0;
          expungeStaleEntries();
          return size;
      }
      

      此處的expungeStaleEntries即移除方法,具體的邏輯可以由以下的流程來描述:

      • A:使用一個繼承于WeakReference的entry對象表示每一個kv對,其中的原引用對象即我們在放入map中的key值
      • B:為保證效率以及盡可能的不使用key值,hash經過預先計算。這樣在定位數據及重新get時不再需要使用原引用對象
      • C:由queue拿到的事件對象,即這里的entry值。通過entry定位到具體的桶位置,通過鏈表計算將entry的前后重新連接起來(即p.pre.next = p.next)

      因此,這里的引用處理并不是自動的,其實是我們在調用某些方法的時候處理,所以我們認為它不是一種自動的,只是表面上看起來是這種處理。
      具體的代碼,即將開始的map定義為一個WeakHashMap,最終的輸出類似如下所示:

      9993回收了:java.lang.ref.WeakReference@12aa816
      9994回收了:java.lang.ref.WeakReference@2bd967
      9995回收了:java.lang.ref.WeakReference@13e9593
      weakHashMap.size->4
      

      在上面的代碼中,由于weakhashmap不允許自定義queue,所以上面的監控是針對value的。在weakHashMap中,queue在weakhashmap在內部定義,并且由內部消化使用了。如果我們在自己進一步處理,那就只能自定義類似weakHashMap實現,或者使用反向操作。即在監控到變化之后,自己處理map的kv。

      隊列監控的反向操作

      反向操作,即意味著一個數據變化了,可以通過weakReference對象反向拿相關的數據,從而進行業務的處理。比如,我們可以通過繼承weakReference對象,加入自定義的字段值,額外處理。一個類似weakHashMap如下,這時,我們不再將key值作為弱引用處理,而是封裝在weakReference對象中,以實現額外的處理。

      WeakR對象定義如下:

      //描述一種強key關系的處理,當value值被回收之后,我們可以通過反向引用將key從map中移除的做法
      //即通過在weakReference中加入其所引用的key值,以獲取key信息,再反向移除map信息
      class WeakR extends WeakReference<byte[]> {
          private Object key;
          WeakR(Object key, byte[] referent, ReferenceQueue<? super byte[]> q) {
              super(referent, q);
              this.key = key;
          }
      }
      

      那么,相應的map,我們就使用普通的hashMap,將weakR作為value進行存儲,如下所示:

      final Map<Object, WeakR> hashMap = new HashMap<>();
      for(int i = 0;i < 10000;i++) {
          byte[] bytesKey = new byte[_1M];
          byte[] bytesValue = new byte[_1M];
          hashMap.put(bytesKey, new WeakR(bytesKey, bytesValue, referenceQueue));
      }
      

      相應的隊列,我們則一樣地進行監控,不同的是,我們對獲取的WeakR對象進行了額外的處理,如下所示:

      int cnt = 0;
      WeakR k;
      while((k = (WeakR) referenceQueue.remove()) != null) {
          System.out.println((cnt++) + "回收了:" + k);
          //觸發反向hash remove
          hashMap.remove(k.key);
          //額外對key對象作其它處理,比如關閉流,通知操作等
      }
      

      其實就是拿到反向引用的key值(這里的value已經不存在了),因為kv映射已沒有意義,將其從map中移除掉。同時,我們還可以作其它的操作(具體的操作還沒想到,嘿嘿)

      這個也可以理解為就是一個類似cache的實現。
      在cache中,key不重要并且通常都很少,value才是需要對待的。這里通過監控value變化,反向修改map,以達到控制kv的目的,避免出現無用的kv映射。

      相應的輸出,如下所示:

      9995回收了:com.m_ylf.study.java.reference.TestCase$1WeakR@13c5f83
      9996回收了:com.m_ylf.study.java.reference.TestCase$1WeakR@197558c
      9997回收了:com.m_ylf.study.java.reference.TestCase$1WeakR@164bc7e
      hashMap.size->1
      

      在Google Guava的簡單描述

      在google guava中,實現了一個類似在第4中所對應的操作。同時對于反向操作,通過繼承一個指定的對象(可以理解為weakReference和callback的組合對象),當value值被gc之后,即可以直接在回調中處理業務即可,不需要自己來監控queue。(見FinalizableReference)

      原文地址:https://www.iflym.com/index.php/java-programe/201407140001.html

      posted @ 2021-12-24 22:02  dai.sp  閱讀(317)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产一区二区三区不卡视频| 亚洲精品午夜国产VA久久成人 | 国精偷拍一区二区三区| 亚洲高清WWW色好看美女| 无码一区二区三区免费| 天堂网av成人在线观看| 中文激情一区二区三区四区| 四虎网址| 开心激情站一区二区三区| 亚洲女同精品中文字幕| 在线视频一区二区三区色 | 久久97超碰色中文字幕| 中文字幕免费不卡二区| 狠狠综合久久av一区二| 18女下面流水不遮图| 亚洲国产综合一区二区精品| 日韩精品中文字幕亚洲| 亚洲啪啪精品一区二区的| 一区二区三区精品偷拍| 亚洲人成小说网站色在线| 亚洲欧美综合精品成人网站| 两个人的视频www免费| 国产婷婷精品av在线| 国产偷国产偷亚洲清高网站| 欧洲亚洲成av人片天堂网| 在线中文一区字幕对白| 中文字幕精品亚洲二区| 精品人妻伦一二二区久久| 在线观看潮喷失禁大喷水无码| 亚洲中文无码永久免费| 韩国无码AV片午夜福利| 亚洲精品宾馆在线精品酒店| 亚洲精品一区二区三区蜜臀| 久久人人97超碰人人澡爱香蕉| 免费无码成人AV片在线| 麻豆精品在线| 蜜臀av色欲a片无人一区| 最新日韩精品中文字幕| 中文字幕乱码一区二区免费| 免费人成再在线观看视频| 亚洲欧美激情在线一区|