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

Java弱引用集合WeakHashMap總結

 更新時間:2023年09月07日 11:20:57   作者:feiyingHiei  
這篇文章主要介紹了Java弱引用集合WeakHashMap總結,WeakHashMap利用WeakReference的弱引用特性讓用戶在使用的過程中不會因為沒有釋放Map中的資源而導致內(nèi)存泄露,WeakHashMap實現(xiàn)了Map接口,使用方式和其他的Map相同,需要的朋友可以參考下

前言

WeakHashMap利用WeakReference的弱引用特性讓用戶在使用的過程中不會因為沒有釋放Map中的資源而導致內(nèi)存泄露。

WeakHashMap實現(xiàn)了Map接口,使用方式和其他的Map相同,需要注意的是get方法和size方法的使用。在介紹WeakHashMap之前需要先介紹一下Reference的概念。

1、Reference的實現(xiàn)

public abstract class Reference<T> {
    private T referent;   //對應的引用對象
    volatile ReferenceQueue<? super T> queue; //引用隊列,初始化的時候從外部傳入
    Reference next;  // 當引用對象可達性發(fā)生變化的時候,next會指向當前引用
    transient private Reference<T> discovered;  /* used by VM */
    static private class Lock { } 
    private static Lock lock = new Lock(); //用來同步鎖操作
}

Reference類有四個直接子類,PhantomReference、FinalReference、SoftReference、WeakReference。

其中SoftReference比WeakReference約束要強一些,當內(nèi)存不夠用的時候JVM才會將對應引用的對象刪除掉,而WeakReference在對象引用不可達的時候就會被JVM清理掉,PhantomReference(虛引用)和約束更弱,get方法永遠都返回null,無法像前兩者一樣可以通過get()方法獲取一個強引用,PhantomReference只能用來監(jiān)控對象的GC狀況。

無論哪種Reference,都有一個重要的對象來跟蹤對象的gc動作,這個就是ReferenceQueue。

2、ReferenceQueue的實現(xiàn)

public class ReferenceQueue {
    static private class Lock { }; //鎖對象,用來同步隊列操作
    private Lock lock = new Lock(); 
    private volatile Reference<? extends T> head = null; //頭結點
    private long queueLength = 0; //隊列長度
}

入隊操作

boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
   synchronized (lock) {
        ReferenceQueue<?> queue = r.queue; //獲取reference之前的隊列,如果沒有綁定隊列,那就不需要入隊
        if ((queue == NULL) || (queue == ENQUEUED)) {
            return false;
        }
        assert queue == this;
        r.queue = ENQUEUED;
        r.next = (head == null) ? r : head; //把r從鏈表的頭部插入
        head = r; //頭結點指向r
        queueLength++; //隊列長度+1
        if (r instanceof FinalReference) {
            sun.misc.VM.addFinalRefCount(1);
        }
        lock.notifyAll(); //喚醒刪除線程刪除頭結點
        return true;
    }
}

出隊列的操作相似,每個reference就是鏈表中的一個節(jié)點,next指向下一個reference節(jié)點。

刪除操作

public Reference<? extends T> remove(long timeout)
    throws IllegalArgumentException, InterruptedException
{
    if (timeout < 0) {
        throw new IllegalArgumentException("Negative timeout value");
    }
    synchronized (lock) {
        Reference<? extends T> r = reallyPoll(); //嘗試獲取隊列的頭結點
        if (r != null) return r; //獲取成功,返回
        long start = (timeout == 0) ? 0 : System.nanoTime(); //如果超時時間不為0,就記錄一下當前的開始時間
        for (;;) {
            lock.wait(timeout);
            r = reallyPoll();
            if (r != null) return r;
            if (timeout != 0) {
                long end = System.nanoTime();
                timeout -= (end - start) / 1000_000; //計算一下等待的時間
                if (timeout <= 0) return null; //確認等待是否是超時,如果是就返回,否則就認為是有入隊請求喚醒當前線程,但是當前線程嘗試刪除頭結點失敗了(被其他線程刪除了),那么繼續(xù)嘗試刪除頭結點,再次執(zhí)行循環(huán)中的內(nèi)容直到超時
                start = end;
            }
        }
    }
}

ReferenceQueue是線程安全的,出隊入隊操作都由lock對象來保證線程安全,當用戶線程和jvm線程同時訪問ReferenceQueue的時候不會出現(xiàn)并發(fā)問題。

WeakHashMap

WeakHashMap內(nèi)部同樣是通過一個數(shù)組來實現(xiàn)存儲,解決沖突的方式也是使用拉鏈法,weakHashMap中重新定義了Entry類來存儲kv鍵值對,Entry的實現(xiàn)也是實現(xiàn)WeakHashMap特性的關鍵。

1、Entry的定義

WeakHashMap重新定義了一個entry,這個entry繼承了WeakReference類并且實現(xiàn)了Entry接口,使用該Entry存儲鍵值對不會產(chǎn)生強引用

jvm在垃圾回收的時候不會認為該引用是強引用,會正常的回收對象

Entry的定義如下

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
  V value;          //存儲的value    
  final int hash;   //hash值
  Entry<K,V> next;  //拉鏈法解決沖突,形成單鏈表
  Entry(Object key, V value,ReferenceQueue<Object> queue, int hash, Entry<K,V> next) {
  super(key, queue);   //這里的引用對象是key,跟蹤的是key對象的垃圾回收
  this.value = value;
  this.hash  = hash;
  this.next  = next;
  }
  ...
}

Entry的構造器需要傳入ReferenceQueue,這個queue就可以用來監(jiān)控全局的Entry被清理的情況。

2、清理操作

當對象被垃圾回收的時候,當前Map需要刪除掉對應的Entry,因為Entry此時指向的對象已經(jīng)被回收,所以需要找到被JVM回收的對象對應的Entry并且將Entry對象從Map中移除掉,實現(xiàn)方式是expungeStaleEntries方法

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,根據(jù)entry獲取entry鏈表在table中的索引
            Entry<K,V> prev = table[i]; //找到entry鏈表的頭結點
            Entry<K,V> p = prev;
            while (p != null) {
                Entry<K,V> next = p.next;
                if (p == e) {
                    if (prev == e)
                        table[i] = next; //找到對應節(jié)點
                    else
                        prev.next = next;
                    e.value = null; // Help GC
                    size--;
                    break;
                }
                prev = p;
                p = next;
            }
        }
    }
}

該方法在map中的getTable()、size()和resize()方法中被調(diào)用,每次put或是get的時候都會先執(zhí)行getTable()方法,因此每次讀寫數(shù)據(jù)的時候都會清理掉無用的entry,所以用戶不會獲取到被垃圾回收的清理entry

因此,每次用戶調(diào)用get方法或是size方法的時候,都會觸發(fā)清理操作,所以每次返回的結果可能都不相同,因為內(nèi)部的entry持有的對象已經(jīng)被jvm回收。

線程安全問題

WeakHashMap作為容器本事不是線程安全的,但是在使用過程中,ReferenceQueue可能會被當前業(yè)務線程和JVM線程并發(fā)訪問,ReferenceQueue是線程安全的。

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

相關文章

  • SpringCache之 @CachePut的使用

    SpringCache之 @CachePut的使用

    這篇文章主要介紹了SpringCache之 @CachePut的使用,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • spring boot如何加入mail郵件支持

    spring boot如何加入mail郵件支持

    這篇文章主要介紹了spring boot如何加入mail郵件支持,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • IDEA找不到jdk該如何解決

    IDEA找不到jdk該如何解決

    這篇文章主要給大家介紹了關于IDEA找不到jdk該如何解決的相關資料,剛安裝好IDEA后,我們運行一個項目時候,有時候會遇到顯示找不到Java的JDK,需要的朋友可以參考下
    2023-11-11
  • spring @Scheduled注解的使用誤區(qū)及解決

    spring @Scheduled注解的使用誤區(qū)及解決

    這篇文章主要介紹了spring @Scheduled注解的使用誤區(qū)及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java網(wǎng)絡編程基礎教程之Socket入門實例

    Java網(wǎng)絡編程基礎教程之Socket入門實例

    這篇文章主要介紹了Java網(wǎng)絡編程基礎教程之Socket入門實例,本文講解了創(chuàng)建Socket、Socket發(fā)送數(shù)據(jù)、Socket讀取數(shù)據(jù)、關閉Socket等內(nèi)容,都是最基礎的知識點,需要的朋友可以參考下
    2014-09-09
  • IDEA中設置Run Dashboard方式

    IDEA中設置Run Dashboard方式

    這篇文章主要介紹了IDEA中設置Run Dashboard方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 基于Mock測試Spring MVC接口過程解析

    基于Mock測試Spring MVC接口過程解析

    這篇文章主要介紹了基于Mock測試Spring MVC接口過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Java請求轉發(fā)和請求重定向區(qū)別詳解

    Java請求轉發(fā)和請求重定向區(qū)別詳解

    這篇文章主要介紹了Java請求轉發(fā)和請求重定向區(qū)別詳解,請求轉發(fā)和請求重定向,但二者是完全不同的,所以我們今天就來盤他們的區(qū)別介紹,需要的朋友可以參考一下
    2022-07-07
  • Java關于后端怎么去接收Date、LocalDateTime類型的參數(shù)詳解

    Java關于后端怎么去接收Date、LocalDateTime類型的參數(shù)詳解

    這篇文章主要介紹了java關于后端怎么去接收Date、LocalDateTime類型的參數(shù),文中有詳細的代碼流程,對我們學習或工作有一定的參考價值,需要的朋友可以參考下
    2023-06-06
  • Mybatis-Plus?新增獲取自增列id方式

    Mybatis-Plus?新增獲取自增列id方式

    這篇文章主要介紹了Mybatis-Plus?新增獲取自增列id方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01

最新評論