Java弱键集合WeakHashMap及ConcurrentCache原理详解

 更新时间:2023年09月07日 09:59:12   作者:刘Java  
这篇文章主要介绍了Java弱键集合WeakHashMap及ConcurrentCache原理详解,基于哈希表的Map接口实现,支持null键和值,但是WeakHashMap具有弱键,可用来实现缓存存储,在进行GC的时候会自动回收键值对,需要的朋友可以参考下

1 WeakHashMap 的原理

基于哈希表的Map接口实现,支持null键和值,但是WeakHashMap具有弱键,可用来实现缓存存储,在进行GC的时候会自动回收键值对。

WeakHashMap 的 Entry 节点继承自 WeakReference。put方法插入键值对时,创建Entry节点时,key被WeakReference引用,get方法获取key的时候,实际上是从WeakReference中获取的。

Value正常引用存储,每次创建插入Entry 节点的时候,还会给WeakReference对象关联一个引用队列ReferenceQueue。

/**
 * 已清除的 WeakEntries 的引用队列
 */
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
/**
 * Entry继承了WeakReference,key被WeakReference直接关联
 */
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对象引用,它就是一个弱键。根据Java弱引用的特性,被WeakReference引用的对象在没有其他外部引用关联时,在下一次垃圾回收时将会回收该对象,并且其关联的WeakReference对象也会被加入到相关的引用队列中。

如果某个key因为没有其他外部引用被“回收”了getKey()方法就获取不到key了,就会返回null,其对应的Entry也会被加入到相关的引用队列中去了,此时这个Entry也就访问不到了,看起来整个Entry就像被回收了一样,但是此时这个Entry并没有被回收,因为它还被内部table数组引用了。

**无效的Entry怎么被清除呢? **实际上当我们每次需要操作WeakHashMap时,会先清除无效的Entry,位于 expungeStaleEntries 方法中。table中保存了全部的Entry键值对,而queue中保存被GC回收的Entry键值对,通过比对就能删除table中被GC回收的Entry键值对,这样就能清除无效的Entry了。

2 tomcat的ConcurrentCache

Tomcat的ConcurrentCache就使用了 WeakHashMap 来实现缓存功能。

ConcurrentCache 采取的是分代缓存,其内部保存了两个Map:

  1. 经常使用的对象放入 eden 中,eden 使用 ConcurrentHashMap 实现,不用担心会被回收(伊甸园);
  2. 不常用的对象放入 longterm,longterm 使用 WeakHashMap 实现,这些不常使用的对象会被垃圾收集器回收。
  3. 当调用 get() 方法时,会先从 eden 区获取,如果没有找到的话再到 longterm 获取,当从 longterm 获取到就把对象放入 eden 中,从而保证经常被访问的节点不容易被回收。
  4. 当调用 put() 方法时,如果 eden 的大小超过了 size,那么就将 eden 中的所有对象都放入 longterm 中,利用虚拟机回收掉一部分不经常使用的对象。
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);
    }
}

到此这篇关于Java弱键集合WeakHashMap及ConcurrentCache原理详解的文章就介绍到这了,更多相关WeakHashMap及ConcurrentCache原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java抽象类和普通类区别、 数组跟List的区别解析

    Java抽象类和普通类区别、 数组跟List的区别解析

    这篇文章主要介绍了Java抽象类和普通类区别、 数组跟List的区别,在这里需要注意List是一个接口,不能直接实例化,需要使用具体的实现类来创建对象,本文结合示例代码介绍的非常详细,需要的朋友参考下吧
    2023-09-09
  • Spring中的接口重试机制解析

    Spring中的接口重试机制解析

    这篇文章主要介绍了Spring中的接口重试机制解析,大家在做项目的时候,往往会遇到一些接口由于网络抖动等问题导致接口响应超时等,这时候我们会希望能够按照一定的规则进行接口请求重试,需要的朋友可以参考下
    2024-01-01
  • 浅析Java中为什么要设计包装类

    浅析Java中为什么要设计包装类

    我们知道Java是一个面相对象的编程语言,基本类型并不具有对象的性质,为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作
    2021-06-06
  • java基础之包装类的介绍及使用

    java基础之包装类的介绍及使用

    今天带大家复习Java基础知识,文中对Java包装类作了非常详细的介绍及总结,对正在学习java基础的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • 在SpringBoot中使用MongoDB完成数据存储

    在SpringBoot中使用MongoDB完成数据存储

    本文主要介绍了在SpringBoot中如恶化使用MongoDB完成数据存储,接下来这篇我们将围绕MongoDB进行,MongoDB是一个开源的,面向文档的NoSQL数据库管理系统,使用类似JSON的BSON(二进制JSON)格式来存储数据,具有灵活的数据模型和强大的查询功能,需要的朋友可以参考下
    2023-11-11
  • SpringBoot的SPI机制源码解析

    SpringBoot的SPI机制源码解析

    这篇文章主要为大家介绍了SpringBoot的SPI机制源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • java web实现简易收费站

    java web实现简易收费站

    这篇文章主要为大家详细介绍了java web实现简易收费站,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一
    2020-11-11
  • Mybatis的update更新批量与普通解决方式对比

    Mybatis的update更新批量与普通解决方式对比

    这篇文章主要为大家介绍了Mybatis的update更新批量与普通解决方式对比,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • Java Optional用法面试题精讲

    Java Optional用法面试题精讲

    这篇文章主要为大家介绍了Java Optional用法面试题精讲,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • SpringBoot读取Resource下文件的4种方法

    SpringBoot读取Resource下文件的4种方法

    这篇文章主要介绍了SpringBoot读取Resource下文件的4种方法小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07

最新评论