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

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

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

WeakHashMap和HashMap的區(qū)別

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

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

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

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

即Entry實現(xiàn)了WeakReference類),當WeakHashMap某個鍵不再正常使用時,會被從WeakHashMap自動刪除。

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

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

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

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

具體如下:

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

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

    /**
     * Expunges stale entries from the table.
     *翻譯:刪除過時的條目,即將ReferenceQueue隊列中的對象引用全部在table中給刪除掉
     *思路:如何刪除一個table的節(jié)點e,方法為:首先計算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

往一個WeakHashMap中添加大量的元素

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

第一段代碼,就是HashMap的應用,往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的應用,往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]);
            }
        }
    }

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

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

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

例子說明2

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

看如下的例子,例子的代碼是,在for循環(huán)中每次都new一個WeakHashMap對象,且每個對象實例中只添加一個key和value都是大的數(shù)組對象??磿霈F(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);
            }
        }
    }

上面的運行結果如下:即由于空間不足報異常錯誤。

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

而如下的代碼確能夠正常工作,這兩段代碼的區(qū)別在于下面這段代碼中調用了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+"個map的大小為:"+maps.get(j).size());
                }
            }
        }
    }

可能有人要問了,不是說WeakHashMap具有會自動進行垃圾回收,第一種情況為什么會報OOM異常了,第二種情況會正常工作呢????

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

    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);
        }
    }

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

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

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

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

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

相關文章

  • 以Java代碼為例講解設計模式中的簡單工廠模式

    以Java代碼為例講解設計模式中的簡單工廠模式

    簡單來說,工廠模式就是按照需求來返回一個類型的對象,使用工廠模式的意義就是,如果對象的實例化與代碼依賴太大的話,不方便進行擴展和維護,使用工廠的目的就是使對象的實例化與主程序代碼就行解耦.來具體看一下:
    2016-05-05
  • Java語言描述二叉樹的深度和寬度

    Java語言描述二叉樹的深度和寬度

    這篇文章主要介紹了Java語言描述二叉樹的深度和寬度,具有一定借鑒價值,需要的朋友可以參考下。
    2017-11-11
  • java 線程池的實現(xiàn)原理、優(yōu)點與風險、以及4種線程池實現(xiàn)

    java 線程池的實現(xiàn)原理、優(yōu)點與風險、以及4種線程池實現(xiàn)

    這篇文章主要介紹了java 線程池的實現(xiàn)原理、優(yōu)點與風險、以及4種線程池實現(xiàn)包括了:配置線程池大小配置,線程池的實現(xiàn)原理等,需要的朋友可以參考下
    2023-02-02
  • SpringBoot讀取Resource目錄下文件的四種方式總結

    SpringBoot讀取Resource目錄下文件的四種方式總結

    在Spring?Boot項目中,經常需要獲取resources目錄下的文件,這些文件可以包括配置文件、模板文件、靜態(tài)資源等,本文將介紹四種常用的方法來獲取resources目錄下的文件,需要的朋友可以參考下
    2023-08-08
  • 10個Java程序員熟悉的面向對象設計原則

    10個Java程序員熟悉的面向對象設計原則

    這篇文章主要為大家詳細介紹了Java程序員應當知道的10個面向對象設計原則,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 詳解JAVA8 函數(shù)式接口

    詳解JAVA8 函數(shù)式接口

    這篇文章主要介紹了JAVA8 函數(shù)式接口的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07
  • SpringBoot整合MybatisPlusGernerator實現(xiàn)逆向工程

    SpringBoot整合MybatisPlusGernerator實現(xiàn)逆向工程

    在我們寫項目的時候,我們時常會因為需要創(chuàng)建很多的項目結構而頭疼,本文主要介紹了SpringBoot整合MybatisPlusGernerator實現(xiàn)逆向工程,具有一定的參考價值,感興趣的可以了解一下
    2024-05-05
  • java格式化數(shù)值成貨幣格式示例

    java格式化數(shù)值成貨幣格式示例

    這篇文章主要介紹了java格式化數(shù)值成貨幣格式示例,格式化一個數(shù)值,比如123456789.123,希望顯示成"$123,456,789.123",需要的朋友可以參考下
    2014-04-04
  • IDEA整合jeesite4.x及安裝教程

    IDEA整合jeesite4.x及安裝教程

    本文給大家介紹IDEA整合jeesite4.x及安裝教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • SpringBoot動態(tài)表操作服務的實現(xiàn)代碼

    SpringBoot動態(tài)表操作服務的實現(xiàn)代碼

    在現(xiàn)代的應用開發(fā)中,尤其是在數(shù)據(jù)庫設計不斷變化的情況下,動態(tài)操作數(shù)據(jù)庫表格成為了不可或缺的一部分,在本篇文章中,我們將以一個典型的動態(tài)表操作服務為例,詳細介紹如何在 Spring Boot 中使用 JdbcTemplate 實現(xiàn)動態(tài)表管理,需要的朋友可以參考下
    2025-01-01

最新評論