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

解析WeakHashMap與HashMap的區(qū)別詳解

 更新時間:2013年05月17日 09:15:49   投稿:jingxian  
本篇文章是對WeakHashMap與HashMap的區(qū)別進行了詳細的分析介紹,需要的朋友參考下

WeakHashMap,此種Map的特點是,當除了自身有對key的引用外,此key沒有其他引用那么此map會自動丟棄此值,
見實例:此例子中聲明了兩個Map對象,一個是HashMap,一個是WeakHashMap,同時向兩個map中放入a、b兩個對象,當HashMap  remove掉a 并且將a、b都指向null時,WeakHashMap中的a將自動被回收掉。出現(xiàn)這個狀況的原因是,對于a對象而言,當HashMap  remove掉并且將a指向null后,除了WeakHashMap中還保存a外已經(jīng)沒有指向a的指針了,所以WeakHashMap會自動舍棄掉a,而對于b對象雖然指向了null,但HashMap中還有指向b的指針,所以
WeakHashMap將會保留

復(fù)制代碼 代碼如下:

package test; 
 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.WeakHashMap; 
 
public class Test { 
    public static void main(String[] args) throws Exception { 
        String a = new String("a"); 
        String b = new String("b"); 
        Map weakmap = new WeakHashMap(); 
        Map map = new HashMap(); 
        map.put(a, "aaa"); 
        map.put(b, "bbb"); 
 
         
        weakmap.put(a, "aaa"); 
        weakmap.put(b, "bbb"); 
         
        map.remove(a); 
         
        a=null; 
        b=null; 
         
        System.gc(); 
        Iterator i = map.entrySet().iterator(); 
        while (i.hasNext()) { 
            Map.Entry en = (Map.Entry)i.next(); 
            System.out.println("map:"+en.getKey()+":"+en.getValue()); 
        } 
 
        Iterator j = weakmap.entrySet().iterator(); 
        while (j.hasNext()) { 
            Map.Entry en = (Map.Entry)j.next(); 
            System.out.println("weakmap:"+en.getKey()+":"+en.getValue()); 
             
        } 
    } 
 
     


先把問題說清楚:
WeakHashMap是主要通過expungeStaleEntries這個函數(shù)的來實現(xiàn)移除其內(nèi)部不用的條目從而達到的自動釋放內(nèi)存的目的的.基本上只要對WeakHashMap的內(nèi)容進行訪問就會調(diào)用這個函數(shù),從而達到清除其內(nèi)部不在為外部引用的條目。但是如果預(yù)先生成了WeakHashMap,而在GC以前又不曾訪問該WeakHashMap,那不是就不能釋放內(nèi)存了嗎?
對應(yīng)的兩個測試案例:
WeakHashMapTest1:
復(fù)制代碼 代碼如下:

public class WeakHashMapTest1 {
public static void main(String[] args) throws Exception {
List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
for (int i = 0; i < 1000; i++) {
WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
d.put(new byte[1000][1000], new byte[1000][1000]);
maps.add(d);
System.gc();
System.err.println(i);}}}

由于Java默認內(nèi)存是64M,所以再不改變內(nèi)存參數(shù)的情況下,該測試跑不了幾步循環(huán)就內(nèi)存溢出了。果不其然,WeakHashMap這個時候并沒有自動幫我們釋放不用的內(nèi)存。
WeakHashMapTest2:
復(fù)制代碼 代碼如下:

public class WeakHashMapTest2 {
public static void main(String[] args) throws Exception {
List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
for (int i = 0; i < 1000; i++) {
WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
d.put(new byte[1000][1000], new byte[1000][1000]);
maps.add(d);
System.gc();
System.err.println(i);
for (int j = 0; j < i; j++) {
System.err.println(j + " size" + maps.get(j).size());
}
}
}
}

這次測試輸出正常,不在出現(xiàn)內(nèi)存溢出問題.
問題講清楚了,現(xiàn)在我們來梳理一下.了解清楚其中的奧秘.
WeakHashMap實現(xiàn)弱引用,是因為它的Entry<K,V>是繼承自WeakReference<K>的
在WeakHashMap$Entry<K,V>的類定義及構(gòu)造函數(shù)里面是這樣寫的:
復(fù)制代碼 代碼如下:

private static class Entry<K,V>
extends WeakReference<K>
implements Map.Entry<K,V> Entry(K key, V value, ReferenceQueue<K> queue,int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}

請注意它構(gòu)造父類的語句:“super(key, queue);”,傳入的是key,因此key才是進行弱引用的,value是直接強引用關(guān)聯(lián)在this.value之中.在System.gc()時,key中的byte數(shù)組進行了回收,而value依然保持(value被強關(guān)聯(lián)到entry上,entry又關(guān)聯(lián)在map中,map關(guān)聯(lián)在arrayList中.).
如何證明key中的byte被回收了呢?可以通過內(nèi)存溢出時導出的內(nèi)存鏡像進行分析,也可以通過如下的小測試得出結(jié)論:
把上面的value用小對象代替,
復(fù)制代碼 代碼如下:

for (int i = 0; i < 10000; i++) {
WeakHashMap<byte[][], Object> d = new WeakHashMap<byte[][], Object>();
d.put(new byte[1000][1000], new Object());
maps.add(d); System.gc();
System.err.println(i);
}

上面的代碼,即使執(zhí)行10000次也沒有問題,證明key中的byte數(shù)組確實被回收了。
for循環(huán)中每次都new一個新的WeakHashMap,在put操作后,雖然GC將WeakReference的key中的byte數(shù)組回收了,并將事件通知到了ReferenceQueue,但后續(xù)卻沒有相應(yīng)的動作去觸發(fā) WeakHashMap 去處理 ReferenceQueue
所以 WeakReference 包裝的key依然存在在WeakHashMap中,其對應(yīng)的value也當然存在。
 那value是何時被清除的呢?
對兩個例子進行分析可知,例子二中的maps.get(j).size()觸發(fā)了value的回收,那又如何觸發(fā)的呢.查看WeakHashMap源碼可知,size方法調(diào)用了expungeStaleEntries方法,該方法對vm要回收的的entry(quene中)進行遍歷,并將entry的value置空,回收了內(nèi)存.
所以效果是key在GC的時候被清除,value在key清除后訪問WeakHashMap被清除.
疑問:key的quene與map的quene是同一個quene,poll操作會減少一個reference,那問題是key如果先被清除,expungeStaleEntries遍歷quene時那個被回收的key對應(yīng)的entry還能取出來么???
關(guān)于執(zhí)行System.GC時,key中的byte數(shù)據(jù)如何被回收了,請見WeakReference referenceQuene
WeakHashMap
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
以弱鍵實現(xiàn)的基于哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。
更精確地說,對于一個給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。
丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實現(xiàn)有所不同。
null 值和 null 鍵都被支持。該類具有與 HashMap 類相似的性能特征,并具有相同的效能參數(shù)初始容量 和加載因子。
像大多數(shù)集合類一樣,該類是不同步的??梢允褂?Collections.synchronizedMap 方法來構(gòu)造同步的 WeakHashMap。
該類主要與這樣的鍵對象一起使用,其 equals 方法使用 == 運算符來測試對象標識。
一旦這種鍵被丟棄,就永遠無法再創(chuàng)建了,所以,過段時間后在 WeakHashMap 中查找此鍵是不可能的,不必對其項已移除而感到驚訝。
該類十分適合與 equals 方法不是基于對象標識的鍵對象一起使用,比如,String 實例。
然而,對于這種可重新創(chuàng)建的鍵對象,鍵若丟棄,就自動移除 WeakHashMap 條目,這種表現(xiàn)令人疑惑。
WeakHashMap 類的行為部分取決于垃圾回收器的動作,所以,幾個常見的(雖然不是必需的)Map 常量不支持此類。
因為垃圾回收器在任何時候都可能丟棄鍵,WeakHashMap 就像是一個被悄悄移除條目的未知線程。
特別地,即使對 WeakHashMap 實例進行同步,并且沒有調(diào)用任何賦值方法,在一段時間后 ,size 方法也可能返回較小的值,
對于 isEmpty 方法,可能返回 false,然后返回 true,對于給定的鍵,containsKey 方法可能返回 true 然后返回 false,對于給定的鍵,
get 方法可能返回一個值,但接著返回 null,對于以前出現(xiàn)在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,
對于鍵集、值集、項集進行的檢查,生成的元素數(shù)量越來越少。
WeakHashMap 中的每個鍵對象間接地存儲為一個弱引用的指示對象。因此,不管是在映射內(nèi)還是在映射之外,
只有在垃圾回收器清除某個鍵的弱引用之后,該鍵才會自動移除。
實現(xiàn)注意事項:WeakHashMap 中的值對象由普通的強引用保持。因此應(yīng)該小心謹慎,確保值對象不會直接或間接地強引用其自身的鍵,
因為這會阻止鍵的丟棄。注意,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;
這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強引用第一個值對象的鍵。
然后,分別用 get 進行解包。
該類所有“collection 視圖方法”返回的迭代器均是快速失敗的:在迭代器創(chuàng)建之后,
迭代器都將拋出 ConcurrentModificationException。因此,面對并發(fā)的修改,迭代器很快就完全失敗,
而不是冒著在將來不確定的時間任意發(fā)生不確定行為的風險。
注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發(fā)修改時,不可能作出任何堅決的保證。
快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯誤的,
正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測 bug。
注意1:null 值和 null 鍵都被支持。
注意2:不是線程安全的。
注意3:迭代器的快速失敗行為不能得到保證。
注意4:WeakHashMap是無序的。
注意5:確保值對象不會直接或間接地強引用其自身的鍵,
因為這會阻止鍵的丟棄。但是,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;
這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強引用第一個值對象的鍵,這時就形成了環(huán)路。
然后,分別用 get 進行解包。如實例1.
實例1:
復(fù)制代碼 代碼如下:

import java.lang.ref.WeakReference;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Test {
 /**
  * @param args
  */
 public static void main(String[] args) {
  WeakHashMap<Integer,WeakReference<People>> map=new WeakHashMap<Integer,WeakReference<People>>();
  People p1=new People("robin",1,28);
  People p2=new People("robin",2,29);
  People p3=new People("harry",3,30);
  map.put(new Integer(100), new WeakReference<People>(p1));
  map.put(new Integer(101), new WeakReference<People>(p2));
  map.put(new Integer(1), new WeakReference<People>(p3));
 
  for(WeakReference<People> rp:map.values())
  {
   People p= rp.get();
   System.out.println("people:"+p);
  }
 }
}
class People{
 String name;
 int id;
 int age;
 public People(String name,int id)
 {
  this(name,id,0);
 }
 public People(String name,int id,int age)
 {
  this.name=name;
  this.id=id;
  this.age=age;
 }
 public String toString()
 {
  return id+name+age;
 }
 public boolean equals(Object o)
 {
  if(o==null)
   return false;
  if(!(o instanceof People))
   return false;
  People p=(People)o;
  boolean res=name.equals(p.name);
  if(res)
   System.out.println("name "+name+" is double");
  else
   System.out.println(name+" vS "+p.name);
  return res;
 }
 public int hashCode()
 {
  return name.hashCode();
 }
}

相關(guān)文章

  • Java反射機制的講解

    Java反射機制的講解

    今天小編就為大家分享一篇關(guān)于Java反射機制的講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • 教你java面試時如何聊單例模式

    教你java面試時如何聊單例模式

    這篇文章主要給大家介紹了關(guān)于Java單例模式推薦的幾種模式,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2021-06-06
  • 基于Springboot商品進銷存管理系統(tǒng)的設(shè)計與實現(xiàn)

    基于Springboot商品進銷存管理系統(tǒng)的設(shè)計與實現(xiàn)

    本項目基于springboot實現(xiàn)一個進銷存管理系統(tǒng),主要用戶開設(shè)網(wǎng)店的相關(guān)商品的進貨、銷售、庫存的管理,功能比較完整,需要的可以參考一下
    2022-08-08
  • 詳解shrio的認證(登錄)過程

    詳解shrio的認證(登錄)過程

    這篇文章主要介紹了shrio的認證(登錄)過程,幫助大家更好的理解和使用shrio框架,感興趣的朋友可以了解下
    2021-02-02
  • Springboot web項目打包實現(xiàn)過程解析

    Springboot web項目打包實現(xiàn)過程解析

    這篇文章主要介紹了Springboot web項目打包實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • 詳解JAVA 連等賦值問題

    詳解JAVA 連等賦值問題

    這篇文章主要介紹了JAVA 連等賦值問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Java靜態(tài)方法不具有多態(tài)性詳解

    Java靜態(tài)方法不具有多態(tài)性詳解

    下面小編就為大家?guī)硪黄狫ava靜態(tài)方法不具有多態(tài)性詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • java 使用foreach遍歷集合元素的實例

    java 使用foreach遍歷集合元素的實例

    這篇文章主要介紹了java 使用foreach遍歷集合元素的實例的相關(guān)資料,這里提供實例幫助大家理解如何使用foreach 進行遍歷,希望能幫助到大家,
    2017-08-08
  • Java中反射的學習筆記分享

    Java中反射的學習筆記分享

    反射是Java編程語言中的一個特性。它允許執(zhí)行的Java程序檢查或?操作?自身,并操作程序的內(nèi)部屬性。本文將通過幾個示例帶大家詳細了解一下Java中反射的使用,需要的可以參考一下
    2022-11-11
  • SpringBoot項目如何把接口參數(shù)中的空白值替換為null值(推薦)

    SpringBoot項目如何把接口參數(shù)中的空白值替換為null值(推薦)

    這篇文章主要介紹了SpringBoot項目如何把接口參數(shù)中的空白值替換為null值(推薦),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01

最新評論

图木舒克市| 冀州市| 怀宁县| 平定县| 巴楚县| 贵州省| 和林格尔县| 通辽市| 乐业县| 寻乌县| 汉源县| 东乡| 临泉县| 伊吾县| 钦州市| 临江市| 桂阳县| 汽车| 新巴尔虎右旗| 木里| 宁化县| 蒙山县| 广宗县| 华容县| 北川| 宁化县| 临猗县| 洪洞县| 大同市| 民和| 全州县| 海口市| 伊宁县| 达日县| 保靖县| 林州市| 麻城市| 西林县| 盱眙县| 玛曲县| 无棣县|