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原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring超详细讲解事务和事务传播机制

    Spring超详细讲解事务和事务传播机制

    Spring事务的本质就是对数据库事务的支持,没有数据库事务,Spring是无法提供事务功能的。Spring只提供统一的事务管理接口,具体实现都是由数据库自己实现的,Spring会在事务开始时,根据当前设置的隔离级别,调整数据库的隔离级别,由此保持一致
    2022-06-06
  • IDEA热更新代码的两种方式详解

    IDEA热更新代码的两种方式详解

    本文详解IDEA代码热更新的两种方式:系统配置(需Ultimate版,仅支持新增修改)和插件(JRebel/XRebel,支持全面自动更新),系统需手动刷新,插件可定时自动更新但可能影响性能,需要的朋友可以参考下
    2025-08-08
  • SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据的具体实现

    SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据的具体实现

    ThreadPoolTaskExecutor是Spring提供的任务执行器实现之一,允许开发者配置线程池参数以适应不同的应用场景,创建 ThreadPoolTaskExecutor 实例并设置核心和最大线程数等属性可以优化性能,本文介绍了SpringBoot利用ThreadPoolTaskExecutor批量插入百万级数据的具体实现
    2024-12-12
  • Java中双重检查锁(double checked locking)的正确实现

    Java中双重检查锁(double checked locking)的正确实现

    双重检查锁(Double-Check Locking),顾名思义,通过两次检查,并基于加锁机制,实现某个功能,下面这篇文章主要给大家介绍了关于Java中双重检查锁(double checked locking)的相关资料,需要的朋友可以参考下
    2021-09-09
  • Java使用CountDownLatch实现网络同步请求的示例代码

    Java使用CountDownLatch实现网络同步请求的示例代码

    CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。被将利用CountDownLatch实现网络同步请求,异步同时获取商品信息组装,感兴趣的可以了解一下
    2023-01-01
  • mybatis-plus踩坑之下划线驼峰转换方式

    mybatis-plus踩坑之下划线驼峰转换方式

    MyBatis-Plus默认驼峰转下划线导致实体字段匹配失败,关闭该功能后需手动配置映射,建议避免字段使用下划线,若必须则可通过注解、重写toString或调整字段名解决
    2025-08-08
  • Mybatis Plus查询时sql字段名大小写报错的解决

    Mybatis Plus查询时sql字段名大小写报错的解决

    这篇文章主要介绍了Mybatis Plus查询时sql字段名大小写报错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Maven Settings.xml的基本语法详解

    Maven Settings.xml的基本语法详解

    这篇文章主要为大家介绍了Maven Settings.xml的基本语法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 教你用Java Swing实现自助取款机系统

    教你用Java Swing实现自助取款机系统

    今天给大家带来的是关于JAVA的相关知识,文章围绕着如何用Java Swing实现自助取款机系统展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Netty分布式ByteBuf使用的底层实现方式源码解析

    Netty分布式ByteBuf使用的底层实现方式源码解析

    这篇文章主要为大家介绍了Netty分布式ByteBuf使用底层实现方式源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03

最新评论