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

Java的WeakHashMap源碼解析及使用場景詳解

 更新時間:2023年09月06日 10:03:58   作者:李思葦  
這篇文章主要介紹了Java的WeakHashMap源碼解析及使用場景詳解,Map本身生命周期很長,需要長期貯留內(nèi)存中,但Map中的Entry可以刪除,使用時可以從其它地方再次取得,需要的朋友可以參考下

WeakHashMap

目的

讓Map中不再使用的Entry被GC及時回收,釋放內(nèi)存空間

應(yīng)用場景-緩存

應(yīng)用場景:Map本身生命周期很長,需要長期貯留內(nèi)存中,但Map中的Entry可以刪除,使用時可以從其它地方再次取得。

實例:tomcat中的緩存有用到。

源碼解析

先理解HashMap源碼

以及WeakReference:弱引用WeakReference所引用的對象的回收規(guī)則

WeahHashMap與HashMap在代碼實現(xiàn)上的不同點:

  1. WeahHashMap類的 Entry<K, V> 繼承了 WeakReference,并設(shè)置 referent = key。
  2. WeakHashMap類內(nèi)定義了一個ReferenceQueue refQueue,每個entry創(chuàng)建時,都會綁定這個refQueue,當(dāng)GC清理了entry的 referent 后,也就是說entry與自己的key斷開引用了,會將entry入隊到其綁定的 refQueue中去。 WeahkHashMap類內(nèi)的任何操作執(zhí)行前(如:get / size 等操作),都會先檢查一遍這個refQueue,將已經(jīng)被GC斷開了對key的引用的entry全都從map中remove掉。
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();	// 定義一個隊列,GC會自動將綁定到了此隊列的weak實例入隊到此隊列,用戶應(yīng)當(dāng)在每次訪問weak實例前,都要檢查實例是否已經(jīng)被GC入隊到此隊列中,如果是,說明實例已經(jīng)被GC,應(yīng)當(dāng)放棄使用。
	...
	private static class Entry<K,V> extends WeakHashMap<Object> implements Map.Entry<K,V>{
		V value;
		int hash;
		Entry<K,V> next;
		Entry(Object key, V value, ReferenceQueue queue, int hash, Entry<K,V> next){
			super(key, queue);	// 調(diào)用父類WeakReference的構(gòu)造方法,設(shè)置referent = key, queue = refQueue;
			this.value = value; 
			this.hash = hash;
			this.next = next;
		}
	}

具體如下:

1.在WeakHashMap類中定義了一個實例域ReferenceQueue<Map.Entry> queue。

   /**
     * Reference queue for cleared WeakEntries
     */
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

2.定義了一個內(nèi)部類WeakHashMap.Entry,直接繼承了WeakReference,Entry中沒有定義key字段,而是調(diào)用super(key,queue),將 key 保存在Reference類的referent字段中。

3.由于Entry本身對key是弱引用,因此GC會監(jiān)測key,在某個Entry的key處于適當(dāng)狀態(tài)時,Entry會被加入到pending列表,然后由ReferenceHandler將Entry添加到queue隊列。

4.WeakHashMap中的許多操作,比如get(K key),size(),remove(K key)時,都會先調(diào)用expungeStaleEntries();方法,這個方法會將已經(jīng)被添加到queue中的Entry從map中移除,同時會將entry的value變量的值置為null。

5.經(jīng)過步驟4,entry被從Map中移除后,不再有對此entry的引用,entry對key即referent的引用是弱引用,entry的value的值被賦值為null,原來的value的對象也不再被引用。GC就可以回收這些對象了。

代碼詳解

  • 自定義的內(nèi)部類Entry<K,V>,實現(xiàn)了Map.Entry<K,V>,同時繼承了WeakReference。其referent指向key。也就是說,WeakHahsMap中的每個Entry都是一個weakRefer實例。

可以看到代碼中沒有定義實例域key,而是調(diào)用WeakReference的構(gòu)造函數(shù)super(key,queue),使得weakRefer實例的referent變量指向了key。

Entry的getKey()方法,就是調(diào)用WeakReference的get()方法,返回referent引用的key。

put(k, v)方法執(zhí)行,構(gòu)造Entry時,會將給定的key賦值給referent。

get( k) 方法執(zhí)行時,根據(jù) k.hash == entry.hash && k.equals(entry.get()) 來比較和查找,其中entry.get()得到的就是referent引用的key。

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
	 V value;
        final int hash;
        Entry<K,V> next;
        /**
         * Creates new entry.
         */
        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }
	@SuppressWarnings("unchecked")
        public K getKey() {
            return (K) WeakHashMap.unmaskNull(get());
        }
        public int hashCode() {      /* 重寫實現(xiàn)了Object類中的hashCode,此方法是計算整個Entry實例對象的hashCode,不是計算key的hashCode */
            K k = getKey();
            V v = getValue();
            return Objects.hashCode(k) ^ Objects.hashCode(v);
        }
}

類中定義了一個聲明的同時也初始化了的ReferenceQueue類型的變量: private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

  • WeakHashMap中的所有Entry的key都會在super(key,queue)時,注冊到此queue上。GC線程會監(jiān)測這些key的可達(dá)性的狀態(tài),在key處于一個特殊狀態(tài)時,就會將引用key的WeakReference實例對象的狀態(tài)設(shè)置為pending,并將WeakReference實例添加到pengding列表中去。而Reference類創(chuàng)建的ReferenceHandler線程則會自旋處理pending列表中的所有處于pending狀態(tài)的Reference實例,將它們enqueue()到queue中去,最終GC會回收queue里的所有Reference實例,由于是Entry實現(xiàn)了WeakReference,因此最終是整個entry被回收。
  • 獲取WeakHashMap的table[]數(shù)組時,會將已經(jīng)被GC入隊的key關(guān)聯(lián)的entry從map中刪除。
private Entry<K,V>[] getTable(){
	Entry<K,V>[] table = expungeStaleEntries();
	return table;
}
/**
     * Expunges stale entries from the 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;
                }
            }
        }
    }

get(K key)時,會調(diào)用Reference的get()獲得Entry真正的key,與參數(shù)key做比較

   public V get(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null) {
            if (e.hash == h && eq(k, e.get()))
                return e.value;
            e = e.next;
        }
        return null;
    }

實例解析:WeakHashMap在tomcat的緩存中的應(yīng)用

public final class ConcurrentCache<K,V>{
	private  final int size;
	private  final Map<K,V> eden;    //新創(chuàng)建的,最近使用的,放在eden里。
	private final Map<K,V> longTerm;    // 當(dāng)eden滿了后,將eden里的所有對象移動到longTerm里。longTerm是一個WeakHashMap,GC及時清理其中的數(shù)據(jù)。
	public ConcurrentCache(int  size){
		this.size=size;
		eden= new ConcurrentHashMap(size);
		longTerm = new WeakHashMap();
	}
	public V get(K k){     /* 被get,最新被使用了,必須要在eden中*/
		V v = eden.get(k) ;
		if(v==null){
			synchronized(longTerm){
			  v = longTerm.get(k);			
			}
			if(v!=null){
				eden.put(k,v);
			}		    
		}
		return v;	
	}
	public V put(K K,V v){   /*最新創(chuàng)建的,放到eden中*/
		if(eden.size()>=size){
			synchronized(longTerm){
				longTerm.putAll(eden);
			}
			eden.clear();
		}
		eden.put(k,v);
	}
}

get時,如果eden中沒有,而longTerm中有,則將數(shù)據(jù)取出后,再添加到eden中,保證最新最近使用的放在eden中。

put時,如果eden已經(jīng)滿了,就將eden中的全部倒換到longTerm中去,將新創(chuàng)建的這個要put到eden中。

如此,longTerm中就是長期未使用的、不常用的,因此用WeakHashMap以便GC回收,釋放空間。

緩存使用 ConcurrentHashMap 和 synchronized(longTerm) 很簡單地實現(xiàn)了多線程安全的緩存。

到此這篇關(guān)于Java的WeakHashMap源碼解析及使用場景詳解的文章就介紹到這了,更多相關(guān)Java的WeakHashMap內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis如何使用動態(tài)語句實現(xiàn)批量刪除(delete結(jié)合foreach)

    Mybatis如何使用動態(tài)語句實現(xiàn)批量刪除(delete結(jié)合foreach)

    這篇文章主要介紹了Mybatis如何使用動態(tài)語句實現(xiàn)批量刪除(delete結(jié)合foreach),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 深入理解hibernate的三種狀態(tài)

    深入理解hibernate的三種狀態(tài)

    本篇文章主要介紹了深入理解hibernate的三種狀態(tài) ,主要包括了transient(瞬時狀態(tài)),persistent(持久化狀態(tài))以及detached(離線狀態(tài)),有興趣的同學(xué)可以了解一下
    2017-05-05
  • 一文帶你玩轉(zhuǎn)Java異常處理

    一文帶你玩轉(zhuǎn)Java異常處理

    這篇文章主要為大家介紹一下Java中的異常處理機(jī)制,文中通過示例為大家進(jìn)行了詳細(xì)的介紹,對我們學(xué)習(xí)有一定的幫助,感興趣的可以了解一下
    2022-08-08
  • SpringBoot整合RabbitMQ 手動應(yīng)答(簡單demo)

    SpringBoot整合RabbitMQ 手動應(yīng)答(簡單demo)

    這篇文章主要介紹了SpringBoot整合RabbitMQ 手動應(yīng)答 簡單demo,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 如何手動安裝Gradle并配置IDEA使用Gradle構(gòu)建

    如何手動安裝Gradle并配置IDEA使用Gradle構(gòu)建

    本文給大家分享手動安裝Gradle并配置IDEA使用Gradle構(gòu)建的步驟,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-04-04
  • SpringBoot實現(xiàn)過濾敏感詞的示例代碼

    SpringBoot實現(xiàn)過濾敏感詞的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot實現(xiàn)過濾敏感詞功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動手嘗試一下
    2022-08-08
  • java多種幻燈片切換特效(經(jīng)典)

    java多種幻燈片切換特效(經(jīng)典)

    功能說明: 代碼實現(xiàn)了多種幻燈片變換特效. 如:淡入淡出、緩慢覆蓋、旋轉(zhuǎn)覆蓋等10多種變換效果。
    2013-03-03
  • Java并發(fā)編程之鎖、并發(fā)容器、阻塞隊列與異步編程實戰(zhàn)代碼

    Java并發(fā)編程之鎖、并發(fā)容器、阻塞隊列與異步編程實戰(zhàn)代碼

    這篇文章主要介紹了Java并發(fā)編程之鎖、并發(fā)容器、阻塞隊列與異步編程的相關(guān)資料,分別是ReentrantLock的靈活鎖機(jī)制、ConcurrentHashMap的高性能并發(fā)設(shè)計、BlockingQueue的生產(chǎn)者、消費者模式及CompletableFuture的異步編程能力,需要的朋友可以參考下
    2026-06-06
  • 詳解Vue與Spring?Boot前后端是怎么對接起來的

    詳解Vue與Spring?Boot前后端是怎么對接起來的

    這篇文章主要介紹了Vue與Spring?Boot前后端是怎么對接起來的相關(guān)資料,通過Vue與SpringBoot案例演示Axios調(diào)用接口,強(qiáng)調(diào)職責(zé)分離與工程結(jié)構(gòu),需要的朋友可以參考下
    2025-06-06
  • Java對象和Map之間相互轉(zhuǎn)換的五種方法

    Java對象和Map之間相互轉(zhuǎn)換的五種方法

    在Java開發(fā)中,經(jīng)常需要將Java對象轉(zhuǎn)換成Map,或者反過來將Map轉(zhuǎn)換成Java對象,這種轉(zhuǎn)換在很多場景下都非常有用,比如在序列化和反序列化過程中、在數(shù)據(jù)傳輸和持久化時、或者在進(jìn)行對象屬性的批量操作時,本文將介紹幾種不同的方法來實現(xiàn)Java對象和Map之間的相互轉(zhuǎn)換
    2025-02-02

最新評論

岳阳市| 深泽县| 临潭县| 甘孜| 杭锦后旗| 蓝田县| 利川市| 邹平县| 阿拉善右旗| 康保县| 沙田区| 盐边县| 阜城县| 临漳县| 滨州市| 青铜峡市| 合肥市| 奇台县| 林州市| 丹巴县| 巴马| 龙泉市| 睢宁县| 娄底市| 奇台县| 广河县| 江川县| 开原市| 吴旗县| 黄龙县| 宁明县| 黄大仙区| 天长市| 松原市| 裕民县| 昌邑市| 潍坊市| 景德镇市| 汉中市| 龙胜| 荔浦县|