欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2013年05月17日 09:15:49   作者:  
本篇文章是對WeakHashMap與HashMap的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
WeakHashMap,此種Map的特點(diǎn)是,當(dāng)除了自身有對key的引用外,此key沒有其他引用那么此map會自動(dòng)丟棄此值,
見實(shí)例:此例子中聲明了兩個(gè)Map對象,一個(gè)是HashMap,一個(gè)是WeakHashMap,同時(shí)向兩個(gè)map中放入a、b兩個(gè)對象,當(dāng)HashMap  remove掉a 并且將a、b都指向null時(shí),WeakHashMap中的a將自動(dòng)被回收掉。出現(xiàn)這個(gè)狀況的原因是,對于a對象而言,當(dāng)HashMap  remove掉并且將a指向null后,除了WeakHashMap中還保存a外已經(jīng)沒有指向a的指針了,所以WeakHashMap會自動(dòng)舍棄掉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這個(gè)函數(shù)的來實(shí)現(xiàn)移除其內(nèi)部不用的條目從而達(dá)到的自動(dòng)釋放內(nèi)存的目的的.基本上只要對WeakHashMap的內(nèi)容進(jìn)行訪問就會調(diào)用這個(gè)函數(shù),從而達(dá)到清除其內(nèi)部不在為外部引用的條目。但是如果預(yù)先生成了WeakHashMap,而在GC以前又不曾訪問該WeakHashMap,那不是就不能釋放內(nèi)存了嗎?
對應(yīng)的兩個(gè)測試案例:
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默認(rèn)內(nèi)存是64M,所以再不改變內(nèi)存參數(shù)的情況下,該測試跑不了幾步循環(huán)就內(nèi)存溢出了。果不其然,WeakHashMap這個(gè)時(shí)候并沒有自動(dòng)幫我們釋放不用的內(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)存溢出問題.
總結(jié)來說:WeakHashMap并不是你啥也干他就能自動(dòng)釋放內(nèi)部不用的對象的,而是在你訪問它的內(nèi)容的時(shí)候釋放內(nèi)部不用的對象
問題講清楚了,現(xiàn)在我們來梳理一下.了解清楚其中的奧秘.
WeakHashMap實(shí)現(xiàn)弱引用,是因?yàn)樗腅ntry<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才是進(jìn)行弱引用的,value是直接強(qiáng)引用關(guān)聯(lián)在this.value之中.在System.gc()時(shí),key中的byte數(shù)組進(jìn)行了回收,而value依然保持(value被強(qiáng)關(guān)聯(lián)到entry上,entry又關(guān)聯(lián)在map中,map關(guān)聯(lián)在arrayList中.).
如何證明key中的byte被回收了呢?可以通過內(nèi)存溢出時(shí)導(dǎo)出的內(nèi)存鏡像進(jìn)行分析,也可以通過如下的小測試得出結(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ù)組確實(shí)被回收了。
for循環(huán)中每次都new一個(gè)新的WeakHashMap,在put操作后,雖然GC將WeakReference的key中的byte數(shù)組回收了,并將事件通知到了ReferenceQueue,但后續(xù)卻沒有相應(yīng)的動(dòng)作去觸發(fā) WeakHashMap 去處理 ReferenceQueue
所以 WeakReference 包裝的key依然存在在WeakHashMap中,其對應(yīng)的value也當(dāng)然存在。
 那value是何時(shí)被清除的呢?
對兩個(gè)例子進(jìn)行分析可知,例子二中的maps.get(j).size()觸發(fā)了value的回收,那又如何觸發(fā)的呢.查看WeakHashMap源碼可知,size方法調(diào)用了expungeStaleEntries方法,該方法對vm要回收的的entry(quene中)進(jìn)行遍歷,并將entry的value置空,回收了內(nèi)存.
所以效果是key在GC的時(shí)候被清除,value在key清除后訪問WeakHashMap被清除.
疑問:key的quene與map的quene是同一個(gè)quene,poll操作會減少一個(gè)reference,那問題是key如果先被清除,expungeStaleEntries遍歷quene時(shí)那個(gè)被回收的key對應(yīng)的entry還能取出來么???
關(guān)于執(zhí)行System.GC時(shí),key中的byte數(shù)據(jù)如何被回收了,請見WeakReference referenceQuene
WeakHashMap
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
以弱鍵實(shí)現(xiàn)的基于哈希表的 Map。在 WeakHashMap 中,當(dāng)某個(gè)鍵不再正常使用時(shí),將自動(dòng)移除其條目。
更精確地說,對于一個(gè)給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。
丟棄某個(gè)鍵時(shí),其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實(shí)現(xiàn)有所不同。
null 值和 null 鍵都被支持。該類具有與 HashMap 類相似的性能特征,并具有相同的效能參數(shù)初始容量 和加載因子。
像大多數(shù)集合類一樣,該類是不同步的??梢允褂?Collections.synchronizedMap 方法來構(gòu)造同步的 WeakHashMap。
該類主要與這樣的鍵對象一起使用,其 equals 方法使用 == 運(yùn)算符來測試對象標(biāo)識。
一旦這種鍵被丟棄,就永遠(yuǎn)無法再創(chuàng)建了,所以,過段時(shí)間后在 WeakHashMap 中查找此鍵是不可能的,不必對其項(xiàng)已移除而感到驚訝。
該類十分適合與 equals 方法不是基于對象標(biāo)識的鍵對象一起使用,比如,String 實(shí)例。
然而,對于這種可重新創(chuàng)建的鍵對象,鍵若丟棄,就自動(dòng)移除 WeakHashMap 條目,這種表現(xiàn)令人疑惑。
WeakHashMap 類的行為部分取決于垃圾回收器的動(dòng)作,所以,幾個(gè)常見的(雖然不是必需的)Map 常量不支持此類。
因?yàn)槔厥掌髟谌魏螘r(shí)候都可能丟棄鍵,WeakHashMap 就像是一個(gè)被悄悄移除條目的未知線程。
特別地,即使對 WeakHashMap 實(shí)例進(jìn)行同步,并且沒有調(diào)用任何賦值方法,在一段時(shí)間后 ,size 方法也可能返回較小的值,
對于 isEmpty 方法,可能返回 false,然后返回 true,對于給定的鍵,containsKey 方法可能返回 true 然后返回 false,對于給定的鍵,
get 方法可能返回一個(gè)值,但接著返回 null,對于以前出現(xiàn)在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,
對于鍵集、值集、項(xiàng)集進(jìn)行的檢查,生成的元素?cái)?shù)量越來越少。
WeakHashMap 中的每個(gè)鍵對象間接地存儲為一個(gè)弱引用的指示對象。因此,不管是在映射內(nèi)還是在映射之外,
只有在垃圾回收器清除某個(gè)鍵的弱引用之后,該鍵才會自動(dòng)移除。
實(shí)現(xiàn)注意事項(xiàng):WeakHashMap 中的值對象由普通的強(qiáng)引用保持。因此應(yīng)該小心謹(jǐn)慎,確保值對象不會直接或間接地強(qiáng)引用其自身的鍵,
因?yàn)檫@會阻止鍵的丟棄。注意,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;
這就是說,某個(gè)值對象可能強(qiáng)引用某個(gè)其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強(qiáng)引用第一個(gè)值對象的鍵。
處理此問題的一種方法是,在插入前將值自身包裝在 WeakReferences 中,如:m.put(key, new WeakReference(value)),
然后,分別用 get 進(jìn)行解包。
該類所有“collection 視圖方法”返回的迭代器均是快速失敗的:在迭代器創(chuàng)建之后,
如果從結(jié)構(gòu)上對映射進(jìn)行修改,除非通過迭代器自身的 remove 或 add 方法,其他任何時(shí)間任何方式的修改,
迭代器都將拋出 ConcurrentModificationException。因此,面對并發(fā)的修改,迭代器很快就完全失敗,
而不是冒著在將來不確定的時(shí)間任意發(fā)生不確定行為的風(fēng)險(xiǎn)。
注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發(fā)修改時(shí),不可能作出任何堅(jiān)決的保證。
快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯(cuò)誤的,
正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測 bug。
注意1:null 值和 null 鍵都被支持。
注意2:不是線程安全的。
注意3:迭代器的快速失敗行為不能得到保證。
注意4:WeakHashMap是無序的。
注意5:確保值對象不會直接或間接地強(qiáng)引用其自身的鍵,
因?yàn)檫@會阻止鍵的丟棄。但是,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;
這就是說,某個(gè)值對象可能強(qiáng)引用某個(gè)其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強(qiáng)引用第一個(gè)值對象的鍵,這時(shí)就形成了環(huán)路。
處理此問題的一種方法是,在插入前將值自身包裝在WeakReferences中,如:m.put(key, new WeakReference(value)),
然后,分別用 get 進(jìn)行解包。如實(shí)例1.
實(shí)例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 前臺加后臺精品圖書管理系統(tǒng)的實(shí)現(xiàn)

    Java 前臺加后臺精品圖書管理系統(tǒng)的實(shí)現(xiàn)

    相信每一個(gè)學(xué)生學(xué)編程的時(shí)候,應(yīng)該都會寫一個(gè)小項(xiàng)目——圖書管理系統(tǒng)。為什么這么說呢?我認(rèn)為一個(gè)學(xué)校的氛圍很大一部分可以從圖書館的氛圍看出來,而圖書管理系統(tǒng)這個(gè)不大不小的項(xiàng)目,接觸的多,也比較熟悉,不會有陌生感,能夠練手,又有些難度,所以我的小項(xiàng)目也來了
    2021-11-11
  • Java+opencv3.2.0之直方圖均衡詳解

    Java+opencv3.2.0之直方圖均衡詳解

    這篇文章主要為大家詳細(xì)介紹了Java+opencv3.2.0之直方圖均衡的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 有關(guān)Java中的BeanInfo介紹

    有關(guān)Java中的BeanInfo介紹

    Java的BeanInfo在工作中并不怎么用到,我也是在學(xué)習(xí)spring源碼的時(shí)候,發(fā)現(xiàn)SpringBoot啟動(dòng)時(shí)候會設(shè)置一個(gè)屬叫"spring.beaninfo.ignore",網(wǎng)上一些地方說這個(gè)配置的意思是是否跳過java BeanInfo的搜索,但是BeanInfo又是什么呢?本文我們將對此做一個(gè)詳細(xì)介紹
    2021-09-09
  • Java8 使用 stream().sorted()對List集合進(jìn)行排序的操作

    Java8 使用 stream().sorted()對List集合進(jìn)行排序的操作

    這篇文章主要介紹了Java8 使用 stream().sorted()對List集合進(jìn)行排序的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Spring?Boot常用注解(經(jīng)典干貨)

    Spring?Boot常用注解(經(jīng)典干貨)

    Spring?Boot是一個(gè)快速開發(fā)框架,快速的將一些常用的第三方依賴整合,全部采用注解形式,內(nèi)置Http服務(wù)器,最終以Java應(yīng)用程序進(jìn)行執(zhí)行,這篇文章主要介紹了Spring?Boot常用注解(絕對經(jīng)典),需要的朋友可以參考下
    2023-01-01
  • 小米Java程序員第二輪面試10個(gè)問題 你是否會被刷掉?

    小米Java程序員第二輪面試10個(gè)問題 你是否會被刷掉?

    小米Java程序員第二輪面試10個(gè)問題,你是否會被刷掉?掌握好基礎(chǔ)知識,祝大家面試順利
    2017-11-11
  • JUnit5相關(guān)內(nèi)容簡介

    JUnit5相關(guān)內(nèi)容簡介

    這篇文章主要介紹了JUnit5相關(guān)內(nèi)容簡介,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Java防止文件被篡改之文件校驗(yàn)功能的實(shí)例代碼

    Java防止文件被篡改之文件校驗(yàn)功能的實(shí)例代碼

    這篇文章主要介紹了Java防止文件被篡改之文件校驗(yàn)功能,本文給大家分享了文件校驗(yàn)和原理及具體實(shí)現(xiàn)思路,需要的朋友可以參考下
    2018-11-11
  • springboot+jwt實(shí)現(xiàn)token登陸權(quán)限認(rèn)證的實(shí)現(xiàn)

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

    這篇文章主要介紹了springboot+jwt實(shí)現(xiàn)token登陸權(quán)限認(rèn)證的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java JVM中線程狀態(tài)詳解

    Java JVM中線程狀態(tài)詳解

    這篇文章主要介紹了Java JVM中線程狀態(tài)詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2022-09-09

最新評論