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

