HashMap evict 放逐之旅

HashMap evict 放逐之旅

我不认识的evict

正在撸猫写代码的我,遇到了一个LinkedHashMap ConcurrentModifyException,真是让人头秃。问题排查过程也是费了一些力气(手动狗头),最后发现是我异步请求接口时,同步修改了同一个map,所以主流程代码在读这个map的时候,会偶发性的出现ConcurrentModifyException(如果有人感兴趣排查过程,评论区留言,后续更贴)。
就在我在解决这个问题的时候,就遇到了Map深复制这个情况,我需要copy一份map用于异步请求的时候用。智能的Intellij 告诉我,我可以在初始化的时候传入map,我一直很相信我的得力助手,所以就这样一顿操作,调试运行没有问题,晚上又可以早点下班了。
但深复制这个情况,我还是需要从源码的角度确认一下,就看了LinkedHashMap初始化的代码

public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);
 }

各位看官这个m肯定没有问题,但是这第二个参数传了一个false,给的注释是

evict false when initially constructing this map, else true (relayed to method afterNodeInsertion).

机智的我查了一下这个单词的意思
evict单词解释
evict这个变量当在map初始化的时候是false,其他情况为true,传递给afterNodeInsection方法。

void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
 }
 
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
}

然后这removeEldestEntry给了一大串注释,我就总结一下:我提供了方式给你重写在添加一个新元素之后删除map中最老的元素。然后作者说了一句话

this is useful if the map represents a cache: it allows the map to reduce memory consumption by deleting stale entries.

对于这个Cache,我搜索了一下,发现LinkedHashMap 可以作为LRU算法实现的数据结构。

LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰

关于LRU算法,看官们可以自行学习了解。

小结

最后总结一下,evict这个变量当在map构造器传入指定map初始化的时候是false,其他情况为true,也即其他构造器创建map之后再调用put方法,该参数则为true。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Java中的Map接口提供了一种将键映射到值的对象。其中一种实现是HashMap,它使用哈希表来实现。HashMap允许 null 键和 null 值,并且没有顺序保证。HashMap 的操作复杂度为 O(1) 平均复杂度,因此在许多情况下非常高效。 ### 回答2: Java集合类中的Map用来保存键-值对,HashMap是其中的一种实现方式。HashMap的内部实现是基于哈希表的,它可以将任意对象作为键,并且保证键的唯一性。在HashMap中,键和值都允许为null,但是同一个HashMap中,键不能重复,如果重复了,新的value会覆盖旧的value。 HashMap内部是通过hashCode()和equals()方法来判断键是否相等的。当我们向HashMap中添加一个键-值对时,系统会先计算出键的hashCode值,然后用该值来确定存放该键值对的位置。如果有多个键的hashCode值相同,称为哈希冲突,那么HashMap会在这些键值对所在的位置上,以链表的形式组成一个链表存储。 HashMap的优点在于插入、删除和查找都比较快,时间复杂度均为O(1),对于大量的数据,它的效率优于List或Set等集合。但是,在内存使用上,HashMap会比List或Set等集合耗费更多的内存空间,因为它需要额外的空间来存储哈希值和链表指针。 值得注意的是,在多线程环境下,HashMap是不安全的,会出现并发修改导致的数据不一致问题,这时可以使用ConcurrentHashMap或者加锁机制来保证线程安全。 总之,HashMapJava中非常实用的集合类,适用于大量键值对的存储和检索。我们应该了解HashMap的内部实现原理,并且在使用过程中需要注意其线程安全性等问题。 ### 回答3: Java中的Map是一种键值对的集合,其中每个元素都由一个键和一个值组成。在Map中,每个键必须是唯一的,而值可以重复。 在Map中,HashMap是最常用的实现类之一。它是基于哈希表实现的,可以通过键快速查找值。哈希表是一种支持常数时间快速查找的数据结构,因为它可以将键映射到与其对应的值的位置,因此查找时只需要计算键的哈希码即可找到对应的值。 HashMap的实现类中使用了两个数组来存储键值对:一个数组用于存储键,另一个数组用于存储值。当插入键值对时,首先会将键的哈希码计算出来,然后通过哈希码将键映射到键数组的位置,将值存储在值数组的相同位置。当需要查找一个键时,只需计算其哈希码并定位到键数组的位置,然后从值数组中取出对应的值即可。 与集合一样,HashMap也是线程不安全的,因此在多线程环境下需要使用ConcurrentHashMap或通过synchronized关键字来保证线程安全性。此外,在使用HashMap时应该尽量避免使用null作为键,因为null的哈希码为0,可能与其他非null键的哈希码相同,导致哈希碰撞,影响HashMap的性能。 总之,HashMap是一种高效的键值对集合,通过哈希表实现快速的查找和插入操作。在正确使用和注意安全性的前提下,使用HashMap可以大大提升代码效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值