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

Java中的WeakHashMap詳解

 更新時(shí)間:2023年09月06日 09:37:02   作者:jieniyimiao  
這篇文章主要介紹了Java中的WeakHashMap詳解,WeakHashMap可能平時(shí)使用的頻率并不高,但是你可能聽過WeakHashMap會進(jìn)行自動(dòng)回收吧,下面就對其原理進(jìn)行分析,需要的朋友可以參考下

楔子

WeakHashMap ,此種Map的特點(diǎn)是,當(dāng)除了自身有對key的引用外,此key沒有其他引用那么此map會自動(dòng)丟棄此值,所以比較適合做緩存。

WeakHashMap 的這種特性比較適合實(shí)現(xiàn)類似本地、堆內(nèi)緩存的存儲機(jī)制——緩存的失效依賴于GC收集器的行為

WeakHashMap 的定義如下:

public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>

簡單來說, WeakHashMap 實(shí)現(xiàn)了Map接口,基于 hash-table 實(shí)現(xiàn),在這種Map中,key的類型是 WeakReference 。如果對應(yīng)的key被回收,則這個(gè)key指向的對象會被從Map容器中移除。

WeakHashMap 跟普通的HashMap不同,WeakHashMap的行為一定程度上基于垃圾收集器的行為,因此一些Map數(shù)據(jù)結(jié)構(gòu)對應(yīng)的常識在WeakHashMap上會失效——size()方法的返回值會隨著程序的運(yùn)行變小,isEmpty()方法的返回值會從false變成true等等。

實(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的指針。

弱引用( WeakReference )的特性是:當(dāng)gc線程發(fā)現(xiàn)某個(gè)對象只有弱引用指向它,那么就會將其銷毀并回收內(nèi)存。

WeakHashMap<UniqueImageName, BigImage> map = new WeakHashMap<>();
BigImage bigImage = new BigImage("image_id");
UniqueImageName imageName = new UniqueImageName("name_of_big_image"); //強(qiáng)引用
map.put(imageName, bigImage);
assertTrue(map.containsKey(imageName));
imageName = null; //map中的values對象成為弱引用對象
System.gc(); //主動(dòng)觸發(fā)一次GC
await().atMost(10, TimeUnit.SECONDS).until(map::isEmpty);

在這里插入圖片描述

典型使用場景: tomcat兩級緩存

tomcat的源碼里,實(shí)現(xiàn)緩存時(shí)會用到WeakHashMap

package org.apache.tomcat.util.collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
public final class ConcurrentCache<K,V> {
    private final int size;
    private final Map<K,V> eden;
    private final Map<K,V> longterm;
    public ConcurrentCache(int size) {
        this.size = size;
        this.eden = new ConcurrentHashMap<>(size);
        this.longterm = new WeakHashMap<>(size);
    }
    public V get(K k) {
        V v = this.eden.get(k);
        if (v == null) {
            synchronized (longterm) {
                v = this.longterm.get(k);
            }
            if (v != null) {
                this.eden.put(k, v);
            }
        }
        return v;
    }
    public void put(K k, V v) {
        if (this.eden.size() >= size) {
            synchronized (longterm) {
                this.longterm.putAll(this.eden);
            }
            this.eden.clear();
        }
        this.eden.put(k, v);
    }
}

源碼中有 eden 和 longterm 的兩個(gè)map,對jvm堆區(qū)有所了解的話,可以猜測出tomcat在這里是使用 ConcurrentHashMap 和 WeakHashMap 做了 分代的緩存 。

  • 在put方法里,在插入一個(gè)k-v時(shí),先檢查eden緩存的容量是不是超了。沒有超就直接放入eden緩存,如果超了則鎖定longterm將eden中所有的k-v都放入longterm。再將eden清空并插入k-v。
  • 在get方法中,也是優(yōu)先從eden中找對應(yīng)的v,如果沒有則進(jìn)入longterm緩存中查找,找到后就加入eden緩存并返回。

經(jīng)過這樣的設(shè)計(jì),相對常用的對象都能在eden緩存中找到,不常用(有可能被銷毀的對象)的則進(jìn)入longterm緩存。而longterm的key的實(shí)際對象沒有其他引用指向它時(shí),gc就會自動(dòng)回收heap中該弱引用指向的實(shí)際對象,弱引用進(jìn)入引用隊(duì)列。longterm調(diào)用expungeStaleEntries()方法,遍歷引用隊(duì)列中的弱引用,并清除對應(yīng)的Entry,不會造成內(nèi)存空間的浪費(fèi)。

利用WeakHashMap實(shí)現(xiàn)內(nèi)存緩存

可以看出,WeakHashMap的這種特性比較適合實(shí)現(xiàn)類似本地、堆內(nèi)緩存的存儲機(jī)制——緩存的失效依賴于GC收集器的行為。假設(shè)一種應(yīng)用場景:我們需要保存一批大的圖片對象,其中values是圖片的內(nèi)容,key是圖片的名字,這里我們需要選擇一種合適的容器保存這些對象。

使用普通的HashMap并不是好的選擇,這些大對象將會占用很多內(nèi)存,并且還不會被GC回收,除非我們在對應(yīng)的key廢棄之前主動(dòng)remove掉這些元素。WeakHashMap非常適合使用在這種場景下,下面的代碼演示了具體的實(shí)現(xiàn):

WeakHashMap<UniqueImageName, BigImage> map = new WeakHashMap<>();
BigImage bigImage = new BigImage("image_id");
UniqueImageName imageName = new UniqueImageName("name_of_big_image"); //強(qiáng)引用
map.put(imageName, bigImage);
assertTrue(map.containsKey(imageName));
imageName = null; //map中的values對象成為弱引用對象
System.gc(); //主動(dòng)觸發(fā)一次GC
await().atMost(10, TimeUnit.SECONDS).until(map::isEmpty);

首先,創(chuàng)建一個(gè)WeakHashMap對象來存儲BigImage實(shí)例,對應(yīng)的key是UniqueImageName對象,保存到WeakHashMap里的時(shí)候,key是一個(gè)弱引用類型。

然后,我們將imageName設(shè)置為null,這樣就沒有其他強(qiáng)引用指向bigImage對象,按照WeakHashMap的規(guī)則,在下一次GC周期中會回收bigImage對象。

通過System.gc()主動(dòng)觸發(fā)一次GC過程,然后可以發(fā)現(xiàn)WeakHashMap成為空的了。

強(qiáng)引用、軟引用和弱引用

  • 強(qiáng)引用( Strong Reference )
  • 軟引用( Soft Reference )
  • 弱引用 ( WeakReference )

強(qiáng)引用

被強(qiáng)引用指向的對象,絕對不會被垃圾收集器回收。

Integer prime = 1;

這個(gè)語句中prime對象就有一個(gè)強(qiáng)引用。

軟引用

被 SoftReference 指向的對象可能會被垃圾收集器回收,但是只有在JVM內(nèi)存不夠的情況下才會回收;如下代碼可以創(chuàng)建一個(gè)軟引用:

Integer prime = 1;  
	SoftReference<Integer> soft = new SoftReference<Integer>(prime);
	prime = null;

弱引用

當(dāng)一個(gè)對象僅僅被 WeakReference 引用時(shí),在下個(gè)垃圾收集周期時(shí)候該對象就會被回收。我們通過下面代碼創(chuàng)建一個(gè)WeakReference:

Integer prime = 1;  
	WeakReference<Integer> soft = new WeakReference<Integer>(prime);
	prime = null;

當(dāng)把prime賦值為null的時(shí)候,原prime對象會在下一個(gè)垃圾收集周期中被回收,因?yàn)橐呀?jīng)沒有強(qiáng)引用指向它。

到此這篇關(guān)于Java中的WeakHashMap總結(jié)的文章就介紹到這了,更多相關(guān)Java的WeakHashMap內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mybatis-plugin插件執(zhí)行原理解析

    mybatis-plugin插件執(zhí)行原理解析

    這篇文章主要介紹了mybatis-plugin插件執(zhí)行原理,我們就需要來研究下Executor,ParameterHandler,ResultSetHandler,StatementHandler這4個(gè)對象的具體跟sql相關(guān)的方法,然后再進(jìn)行修改,就可以直接起到aop的作用,需要的朋友可以參考下
    2022-10-10
  • 徹底解決tomcat中文亂碼問題方案

    徹底解決tomcat中文亂碼問題方案

    這篇文章主要介紹了徹底解決tomcat中文亂碼問題方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java內(nèi)部類的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說明

    Java內(nèi)部類的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說明

    這篇文章主要介紹了Java內(nèi)部類的實(shí)現(xiàn)原理與可能的內(nèi)存泄漏說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • java文件上傳下載代碼實(shí)例

    java文件上傳下載代碼實(shí)例

    這篇文章主要介紹了java文件上傳下載,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進(jìn)行排序

    如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進(jìn)行排序

    這篇文章主要介紹了如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進(jìn)行排序問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java 命名規(guī)范(非常全面)

    Java 命名規(guī)范(非常全面)

    在本文中,將從大到小,從外到內(nèi),總結(jié)Java編程中的命名規(guī)范。文中將會涉及到日常工作中常見的命名示例,如包命名,類命名,接口命名,方法命名,變量命名,常類命名,抽象類命名,異常類命名以及擴(kuò)展類命名等。
    2021-09-09
  • idea 離線安裝lombok插件的方法步驟(圖文)

    idea 離線安裝lombok插件的方法步驟(圖文)

    這篇文章主要介紹了idea 離線安裝lombok插件的方法步驟(圖文),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • 硬核 Redis 高頻面試題解析

    硬核 Redis 高頻面試題解析

    Redis 是一個(gè)高性能的key-value數(shù)據(jù)庫。在部分場合可以對關(guān)系數(shù)據(jù)庫起到很好的補(bǔ)充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端使用很方便
    2021-06-06
  • Spring Boot集成Redis實(shí)戰(zhàn)操作功能

    Spring Boot集成Redis實(shí)戰(zhàn)操作功能

    這篇文章主要介紹了Spring Boot集成Redis實(shí)戰(zhàn)操作,包括如何集成redis以及redis的一些優(yōu)點(diǎn),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • 學(xué)習(xí)Java正則表達(dá)式(匹配、替換、查找)

    學(xué)習(xí)Java正則表達(dá)式(匹配、替換、查找)

    這篇文章主要介紹了Java正則表達(dá)式的匹配、替換、查找和切割等操作,對于正則表達(dá)式的匹配、替換大家已經(jīng)不陌生了吧
    2015-12-12

最新評論