Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解
1 WeakHashMap 的原理
基于哈希表的Map接口實(shí)現(xiàn),支持null鍵和值,但是WeakHashMap具有弱鍵,可用來實(shí)現(xiàn)緩存存儲(chǔ),在進(jìn)行GC的時(shí)候會(huì)自動(dòng)回收鍵值對(duì)。
WeakHashMap 的 Entry 節(jié)點(diǎn)繼承自 WeakReference。put方法插入鍵值對(duì)時(shí),創(chuàng)建Entry節(jié)點(diǎn)時(shí),key被WeakReference引用,get方法獲取key的時(shí)候,實(shí)際上是從WeakReference中獲取的。
Value正常引用存儲(chǔ),每次創(chuàng)建插入Entry 節(jié)點(diǎn)的時(shí)候,還會(huì)給WeakReference對(duì)象關(guān)聯(lián)一個(gè)引用隊(duì)列ReferenceQueue。
/** * 已清除的 WeakEntries 的引用隊(duì)列 */ private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); /** * Entry繼承了WeakReference,key被WeakReference直接關(guān)聯(lián) */ 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 V getValue() { return value; } public V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } //………… }
key被WeakReference對(duì)象引用,它就是一個(gè)弱鍵。根據(jù)Java弱引用的特性,被WeakReference引用的對(duì)象在沒有其他外部引用關(guān)聯(lián)時(shí),在下一次垃圾回收時(shí)將會(huì)回收該對(duì)象,并且其關(guān)聯(lián)的WeakReference對(duì)象也會(huì)被加入到相關(guān)的引用隊(duì)列中。
如果某個(gè)key因?yàn)闆]有其他外部引用被“回收”了getKey()方法就獲取不到key了,就會(huì)返回null,其對(duì)應(yīng)的Entry也會(huì)被加入到相關(guān)的引用隊(duì)列中去了,此時(shí)這個(gè)Entry也就訪問不到了,看起來整個(gè)Entry就像被回收了一樣,但是此時(shí)這個(gè)Entry并沒有被回收,因?yàn)樗€被內(nèi)部table數(shù)組引用了。
**無效的Entry怎么被清除呢? **實(shí)際上當(dāng)我們每次需要操作WeakHashMap時(shí),會(huì)先清除無效的Entry,位于 expungeStaleEntries 方法中。table中保存了全部的Entry鍵值對(duì),而queue中保存被GC回收的Entry鍵值對(duì),通過比對(duì)就能刪除table中被GC回收的Entry鍵值對(duì),這樣就能清除無效的Entry了。
2 tomcat的ConcurrentCache
Tomcat的ConcurrentCache就使用了 WeakHashMap 來實(shí)現(xiàn)緩存功能。
ConcurrentCache 采取的是分代緩存,其內(nèi)部保存了兩個(gè)Map:
- 經(jīng)常使用的對(duì)象放入 eden 中,eden 使用 ConcurrentHashMap 實(shí)現(xiàn),不用擔(dān)心會(huì)被回收(伊甸園);
- 不常用的對(duì)象放入 longterm,longterm 使用 WeakHashMap 實(shí)現(xiàn),這些不常使用的對(duì)象會(huì)被垃圾收集器回收。
- 當(dāng)調(diào)用 get() 方法時(shí),會(huì)先從 eden 區(qū)獲取,如果沒有找到的話再到 longterm 獲取,當(dāng)從 longterm 獲取到就把對(duì)象放入 eden 中,從而保證經(jīng)常被訪問的節(jié)點(diǎn)不容易被回收。
- 當(dāng)調(diào)用 put() 方法時(shí),如果 eden 的大小超過了 size,那么就將 eden 中的所有對(duì)象都放入 longterm 中,利用虛擬機(jī)回收掉一部分不經(jīng)常使用的對(duì)象。
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); } }
到此這篇關(guān)于Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解的文章就介紹到這了,更多相關(guān)WeakHashMap及ConcurrentCache原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java網(wǎng)絡(luò)編程基礎(chǔ)知識(shí)介紹
這篇文章主要介紹了java網(wǎng)絡(luò)編程基礎(chǔ)知識(shí)介紹,涉及OSI分層模型和TCP/IP分層模型的對(duì)應(yīng)關(guān)系、IP地址、端口號(hào)、tcp、udp等相關(guān)內(nèi)容,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11springboot中RestTemplate配置HttpClient連接池詳解
這篇文章主要介紹了springboot中RestTemplate配置HttpClient連接池詳解,這些Http連接工具,使用起來都比較復(fù)雜,如果項(xiàng)目中使用的是Spring框架,可以使用Spring自帶的RestTemplate來進(jìn)行Http連接請(qǐng)求,需要的朋友可以參考下2023-11-11Spring boot 應(yīng)用實(shí)現(xiàn)動(dòng)態(tài)刷新配置詳解
這篇文章主要介紹了spring boot 配置動(dòng)態(tài)刷新實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-09-09Java的非阻塞隊(duì)列ConcurrentLinkedQueue解讀
這篇文章主要介紹了Java的非阻塞隊(duì)列ConcurrentLinkedQueue解讀,在并發(fā)編程中,有時(shí)候需要使用線程安全的隊(duì)列,如果要實(shí)現(xiàn)一個(gè)線程安全的隊(duì)列有兩種方式:一種是使用阻塞算法,另一種是使用非阻塞算法,需要的朋友可以參考下2023-12-12Java使用pdfbox實(shí)現(xiàn)給pdf文件加圖片水印
有時(shí)候需要給pdf加水印,市面上工具都是收費(fèi)的要會(huì)員,還是自食其力吧;嘗試過 spire.pdf.free 那個(gè)超過10頁就不行了!所以本文還是使用了pdfbox,感興趣的可以了解一下2022-11-11Java和Ceylon對(duì)象的構(gòu)造和驗(yàn)證
這篇文章主要為大家詳細(xì)介紹了Java和Ceylon對(duì)象的構(gòu)造和驗(yàn)證,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11詳解Nacos中注冊(cè)中心和配置中心的實(shí)現(xiàn)
Spring?Cloud?Alibaba?是阿里巴巴提供的一站式微服務(wù)開發(fā)解決方案。而?Nacos?作為?Spring?Cloud?Alibaba?的核心組件之一,提供了兩個(gè)非常重要的功能:注冊(cè)中心和配置中心,我們今天來了解和實(shí)現(xiàn)一下二者2022-08-08Springboot的maven間接依賴的實(shí)現(xiàn)
這篇文章主要介紹了Springboot的maven間接依賴的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05