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

Java中WeakHashMap和HashMap的區(qū)別詳解

 更新時(shí)間:2023年09月07日 10:04:52   作者:HelloWorld_EE  
這篇文章主要介紹了Java中WeakHashMap和HashMap的區(qū)別詳解,WeakHashMap和HashMap一樣,WeakHashMap也是一個(gè)散列表,它存儲(chǔ)的內(nèi)容也是鍵值對(duì)(key-value)映射,而且鍵和值都可以為null,需要的朋友可以參考下

WeakHashMap和HashMap的區(qū)別

前面對(duì)HashMap的源碼和WeakHashMap的源碼分別進(jìn)行了分析。在WeakHashMap源碼分析博文中有對(duì)與HashMap區(qū)別的比較,但是不夠具體系統(tǒng)。加上本人看了一些相關(guān)的博文,發(fā)現(xiàn)了一些好的例子來說明這兩者的區(qū)別,因此,就有了這篇博文。

WeakHashMap和HashMap一樣,WeakHashMap也是一個(gè)散列表,它存儲(chǔ)的內(nèi)容也是鍵值對(duì)(key-value)映射,而且鍵和值都可以為null。

不過WeakHashMap的鍵是“弱鍵”(注:源碼中Entry中的定義是這樣的:

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>

即Entry實(shí)現(xiàn)了WeakReference類),當(dāng)WeakHashMap某個(gè)鍵不再正常使用時(shí),會(huì)被從WeakHashMap自動(dòng)刪除。

更精確的說,對(duì)于一個(gè)給定的鍵,其映射的存在并不能阻止垃圾回收器對(duì)該鍵的丟棄,這就使該鍵稱為被終止的,被終止,然后被回收,這樣,這就可以認(rèn)為該鍵值對(duì)應(yīng)該被WeakHashMap刪除。因此,WeakHashMap使用了弱引用作為內(nèi)部數(shù)據(jù)的存儲(chǔ)方案

WeakHashMap可以作為簡單緩存表的解決方案,當(dāng)系統(tǒng)內(nèi)存不足時(shí),垃圾收集器會(huì)自動(dòng)的清除沒有在任何其他地方被引用的鍵值對(duì)。如果需要用一張很大的Map作為緩存表時(shí),那么可以考慮使用WeakHashMap。

從源碼的角度,我們來分析下上面這段話是如何來工作的??

在WeakHashMap實(shí)現(xiàn)中,借用了ReferenceQueue這個(gè)“監(jiān)聽器”來保存被GC回收的”弱鍵”,然后在每次使用WeakHashMap時(shí),就在WeakHashMap中刪除ReferenceQueue中保存的鍵值對(duì)。即WeakHashMap的實(shí)現(xiàn)是通過借用 ReferenceQueue這個(gè)“監(jiān)聽器”來優(yōu)雅的實(shí)現(xiàn)自動(dòng)刪除那些引用不可達(dá)的key的。關(guān)于ReferenceQueue會(huì)在下篇博文中進(jìn)行介紹

具體如下:

WeakHashMap是通過數(shù)組table保存Entry(鍵值對(duì));每個(gè)Entry實(shí)際上就是一個(gè)鏈表來實(shí)現(xiàn)的。當(dāng)某“弱鍵”不再被其它對(duì)象引用,就會(huì)被GC回收時(shí),這個(gè)“弱鍵”也同時(shí)被添加到ReferenceQueue隊(duì)列中。當(dāng)下一步我們需要操作WeakHashMap時(shí),會(huì)先同步table、queue,table中保存了全部的鍵值對(duì),而queue中保存的是GC回收的鍵值對(duì);同步他們,就是刪除table中被GC回收的鍵值對(duì)。

源碼中完成“刪除”操作的函數(shù)代碼如下:

    /**
     * Expunges stale entries from the table.
     *翻譯:刪除過時(shí)的條目,即將ReferenceQueue隊(duì)列中的對(duì)象引用全部在table中給刪除掉
     *思路:如何刪除一個(gè)table的節(jié)點(diǎn)e,方法為:首先計(jì)算e的hash值,接著根據(jù)hash值找到其在table的位置,然后遍歷鏈表即可。
     */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);
                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

例子說明1

往一個(gè)WeakHashMap中添加大量的元素

上面說的可能比較空,比如為什么可以作為緩沖表呀之類,可能看一個(gè)實(shí)際例子之后我們就可以更好的理解上面的兩段話

第一段代碼,就是HashMap的應(yīng)用,往HashMap中存放一系列很大的數(shù)據(jù)。

    public class TestHashMap {
        public static void main(String[] args){
            Map<Integer,byte[]> hashMap = new HashMap<Integer,byte[]>();
            for(int i=0;i<100000;i++){
                hashMap.put(i, new byte[i]);
            }
        }
    }

第二段代碼,就是WeakHashMap的應(yīng)用,往WeakHashMap中存放與上例HashMap相同的數(shù)據(jù)。

    public class TestWeakHashMap {
        public static void main(String[] args){
            Map<Integer,byte[]> weakHashMap = new WeakHashMap<Integer,byte[]>();
            for(int i=0;i<100000;i++){
                weakHashMap.put(i, new byte[i]);
            }
        }
    }

運(yùn)行上面的兩段代碼,發(fā)現(xiàn),第一段代碼是不能正常工作的,會(huì)拋“java.lang.OutOfMemoryError: Java heap space”,而第二段代碼就可以正常工作。

以上就說明了,WeakHashMap當(dāng)系統(tǒng)內(nèi)存不足時(shí),垃圾收集器會(huì)自動(dòng)的清除沒有在任何其他地方被引用的鍵值對(duì),因此可以作為簡單緩存表的解決方案。而HashMap就沒有上述功能。

但是,如果WeakHashMap的key在系統(tǒng)內(nèi)持有強(qiáng)引用,那么WeakHashMap就退化為了HashMap,所有的表項(xiàng)都不會(huì)被垃圾回收器回收。

例子說明2

一系列的WeakHashMap,往每個(gè)WeakHashMap中只添加一個(gè)大的數(shù)據(jù)

看如下的例子,例子的代碼是,在for循環(huán)中每次都new一個(gè)WeakHashMap對(duì)象,且每個(gè)對(duì)象實(shí)例中只添加一個(gè)key和value都是大的數(shù)組對(duì)象??磿?huì)出現(xiàn)上面現(xiàn)象???

    public class TestWeakHashMap3 {
        public static void main(String[] args){
            List<WeakHashMap<Integer[][], Integer[][]>> maps = new ArrayList<WeakHashMap<Integer[][],Integer[][]>>();   
            int totalNum = 10000;
            for(int i=0;i<totalNum;i++){
                WeakHashMap<Integer[][], Integer[][]> w = new WeakHashMap<Integer[][], Integer[][]>();
                w.put(new Integer[1000][1000], new Integer[1000][1000]);
                maps.add(w);
                System.gc();//顯示gc
                System.out.println(i);
            }
        }
    }

上面的運(yùn)行結(jié)果如下:即由于空間不足報(bào)異常錯(cuò)誤。

    /*
     * 運(yùn)行結(jié)果:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
     *  at com.wrh.testhashmap.TestWeakHashMap3.main(TestWeakHashMap3.java:15)
     * */

而如下的代碼確能夠正常工作,這兩段代碼的區(qū)別在于下面這段代碼中調(diào)用了WeakHashMap的size()方法。

    public class TestWeakHashMap5 {
        public static void main(String[] args){
            List<WeakHashMap<Integer[][], Integer[][]>> maps = new ArrayList<WeakHashMap<Integer[][],Integer[][]>>();   
            int totalNum = 10000;
            for(int i=0;i<totalNum;i++){
                WeakHashMap<Integer[][], Integer[][]> w = new WeakHashMap<Integer[][], Integer[][]>();
                w.put(new Integer[1000][1000], new Integer[1000][1000]);
                maps.add(w);
                System.gc();
                for(int j=0;j<i;j++){
                    System.out.println("第"+j+"個(gè)map的大小為:"+maps.get(j).size());
                }
            }
        }
    }

可能有人要問了,不是說WeakHashMap具有會(huì)自動(dòng)進(jìn)行垃圾回收,第一種情況為什么會(huì)報(bào)OOM異常了,第二種情況會(huì)正常工作呢????

首先要說明的是,第一段代碼并不是沒有執(zhí)行GC,而是僅對(duì)WeakHashMap中的key中的Integer數(shù)組進(jìn)行了回收,而value依然保持。我們先來看如下的例子:將value換成一個(gè)小的對(duì)象Object,就會(huì)證明這一點(diǎn)內(nèi)容。

    public static void main(String[] args){
        List<WeakHashMap<Integer[][], Object>> maps = new ArrayList<WeakHashMap<Integer[][],Object>>(); 
        int totalNum = 10000;
        for(int i=0;i<totalNum;i++){
            WeakHashMap<Integer[][], Object> w = new WeakHashMap<Integer[][], Object>();
            w.put(new Integer[1000][1000], new Object());
            maps.add(w);
            System.gc();
            System.out.println(i);
        }
    }

上面的代碼運(yùn)行時(shí)沒有任何問題的,這也就證明了key中的Integer數(shù)組確實(shí)被回收了,那為何key中的reference數(shù)據(jù)被GC,卻沒有觸發(fā)WeakHashMap去做清理整個(gè)key的操作呢??

原因是在于:在進(jìn)行put操作后,雖然GC將WeakReference的key中的Integer數(shù)組回收了,并將事件通過到了ReferenceQueue,但是后續(xù)卻沒有相應(yīng)的動(dòng)作去觸發(fā)WeakHashMap來進(jìn)行處理ReferenceQueue,所以WeakReference包裝的key依然存在在WeakHashMap中,其對(duì)應(yīng)的value也就依然存在。

但是在WeakHashMap中會(huì)刪除那些已經(jīng)被GC的鍵值對(duì)在源碼中是通過調(diào)用expungeStaleEntries函數(shù)來完成的,而這個(gè)函數(shù)只在WeakHashMap的put、get、size()等方法中才進(jìn)行了調(diào)用。因此,只有put、get、size()方法來可以觸發(fā)WeakHashMap來進(jìn)行處理ReferenceQueue。

以上也就是為什么上面的第二段代碼中調(diào)用下WeakHashMap的size()方法之后就不會(huì)報(bào)異常能正常工作的原因。

到此這篇關(guān)于Java中WeakHashMap和HashMap的區(qū)別詳解的文章就介紹到這了,更多相關(guān)WeakHashMap和HashMap的區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring @Conditional注解原理解析

    Spring @Conditional注解原理解析

    這篇文章主要介紹了Spring @Conditional注解原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 詳談Map的key、value值的數(shù)據(jù)類型不能為基本類型的原因

    詳談Map的key、value值的數(shù)據(jù)類型不能為基本類型的原因

    這篇文章主要介紹了詳談Map的key、value值的數(shù)據(jù)類型不能為基本類型的原因,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題

    異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題

    這篇文章主要介紹了異常解決SpringBoot項(xiàng)目啟動(dòng)卡住,無任何異常信息問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java獲取Process子進(jìn)程進(jìn)程ID方法詳解

    Java獲取Process子進(jìn)程進(jìn)程ID方法詳解

    這篇文章主要介紹了Java獲取Process子進(jìn)程進(jìn)程ID方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • 15個(gè)高級(jí)Java多線程面試題及回答

    15個(gè)高級(jí)Java多線程面試題及回答

    這篇文章主要介紹了15個(gè)高級(jí)Java多線程面試題及回答,翻譯自國外的一篇文章,這些面試題容易混淆、較難回答,需要的朋友可以參考下吧
    2014-05-05
  • 詳解Spring 注解之@Import 注入的各種花活

    詳解Spring 注解之@Import 注入的各種花活

    這篇文章主要介紹了詳解Spring 注解之@Import 注入的各種花活,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java線程取消的三種方式

    Java線程取消的三種方式

    文章介紹了 Java 線程取消的 3 種方式,不推薦使用 stop 方法和 volatile 設(shè)標(biāo)記位停止線程,線程中斷機(jī)制是協(xié)作式的,一個(gè)線程請(qǐng)求中斷,另一線程響應(yīng),線程可檢查自身中斷狀態(tài)或捕獲 InterruptedException 來合適處理以響應(yīng)中斷,確保安全有序停止,避免資源泄露等問題
    2024-12-12
  • JavaEE組件commons-fileupload實(shí)現(xiàn)文件上傳、下載

    JavaEE組件commons-fileupload實(shí)現(xiàn)文件上傳、下載

    這篇文章主要介紹了JavaEE組件commons-fileupload實(shí)現(xiàn)文件上傳、下載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 使用Spring開啟注解AOP的支持放置的位置

    使用Spring開啟注解AOP的支持放置的位置

    這篇文章主要介紹了使用Spring開啟注解AOP的支持放置的位置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解Java TCC分布式事務(wù)實(shí)現(xiàn)原理

    詳解Java TCC分布式事務(wù)實(shí)現(xiàn)原理

    這篇文章主要介紹了詳解Java TCC分布式事務(wù)實(shí)現(xiàn)原理,對(duì)分布式事務(wù)感興趣的同學(xué),一定要看一下
    2021-04-04

最新評(píng)論

库伦旗| 长沙市| 高阳县| 三亚市| 丰镇市| 应用必备| 襄樊市| 澄城县| 弥渡县| 资阳市| 扶沟县| 乌兰县| 亳州市| 个旧市| 宣化县| 平阴县| 项城市| 万州区| 阜新| 东莞市| 梁平县| 赤城县| 阜新市| 平和县| 丹江口市| 阳朔县| 安福县| 仁化县| 景德镇市| 衡东县| 崇明县| 五常市| 顺义区| 改则县| 博白县| 洪洞县| 松滋市| 综艺| 麻栗坡县| 阳春市| 庄河市|