一、WeakHashMap和HashMap的区别

map是一个表达键-值映射关系集的接口

weakhashmap是 AbstractMap的子类

AbstractMap继承自Object

weakhashmap自动释放无调用的键值。

二、Java中的强引用,软引用,弱引用,虚引用有什么用

这两天在看 Reference 相关的东西,虽然接触到的场景不多,但感觉还是比较有用的。

在非常关心内存的情况下,有可能能派上用场。

在涉及到某一个对象被 GC,需要得到通知,然后再做某些相关处理的时候,有可能派得上用场。

对于第一点,目前接触到的就是 WeakHahsMap。像我们平常写缓存的时候,最简单的就是在一个类中

public static Map user_map = new HashMap();

然后再在全局使用它。这里就可以参考下 Tomcat 实现的这个 LRU 缓存:tomcat/ConcurrentCache.java at trunk · apache/tomcat · GitHub,它就用到了 WeakHashMap,WeakHashMap也用到了 WeakReference,可以参考下。

WeakHahsMap 的实现原理简单来说就是里面的 Entry 使用继承了 WeakReference,那么当 Entry 的 key 不再被使用的时候,也就是被 GC 的时候,那么该 Entry 就会进入到 ReferenceQueue 中, WeakHashMap 在你调用相关方法的时候,那么就会把这个 Entry 从 ReferenceQueue 中删除,并且做相关处理(也就是把这个 key 删除)。这时候你就会发现,你的一个键值对没有了。

对于第二点,目前接触到的就是一个 FileCleaningTracker,它的作用是,把一个文件和一个对象关联起来,当这个对象被 GC 的时候,文件也帮我们删除掉。

FileCleaningTracker 的实现简单来说就是用了一个虚引用。它里面有一个 Tracker 的内部类,他继承自 PhantomReference,你可以理解成 WeakHashMap中的 Entry(其实也很像了)。这个 Tracker 就和我们的关联对象 marker 关联起来(你可以理解成 WeakHashMap 中的 Entry 的 key),那么当 marker 被回收的时候,Tracker 就会被GC 弄到 ReferenceQueue 中,那么 FileCleaningTracker 就会把 Tracker 从 ReferenceQueue 移除出来,并且执行相关操作(delete file)。

最后:

自己理解的引用(强,软,弱虚)是和 GC 比较相关的,能够在一个 对象被 GC 的时候,应用程序得到通知,然后执行相关操作。像 WeakHashMap 就是这样,底层发现 key 没了,上层就把 entry 删了。

ps:

第6条:消除过期对象的引用(WeakHashMap的缓存应用):愿无岁月可回首

第6条:WeakHashMap扩展知识1(原理与Reference相关):愿无岁月可回首

第6条:Reference应用-FileCleaningTracker:愿无岁月可回首

最后的最后补充。。。

突然想起,之前自己在工作中涉及到这样一种情况,我需要对用户投资的钱进行一个每日的加息,有一天客户忘了把加息的数据给我,然后给了我一份 csv 文件,让我加上。我当时的做法是,让运维把文件放在固定的地方,程序读取,执行逻辑,然后运维再手动删除。 这个时候,其实也可以通过这种 FileCleaningTracker,当读取完之后,自动的删除这个文件,就不用运维来做了。(这可能是一种应用场景)

三、WeakHashMap 详解

jdk8

本文讨论java.util.package下 WeakHashMap ,为了更好理解数据结构,使用它可以实现简单缓存,并不建议线上环境使用它来,这里只是来帮助理解weakHashmap原理, WeakHashMap 是用哈希表实现 Map 接口,key是 WeekReference 类型, Entry 在 WeakHashMap 被自动删除当 key 不在被使用时候,意味着 key 对象没有被引用,垃圾回收线程会回收 key 对象, Entry 会从map中移除,因此 WeakhHashMap 是另外一种实现 Map 接口

为了更好理解 WeakHashMap ,需要理解弱引用, put() 方法中会把key变成弱引用,java中主要有3中引用,后面部分会介绍

变量prime强引用Integer对象为1值,任何对象被强引用不会被垃圾回收掉

一个对象是软引用不会被垃圾回收器回收直到jvm虚拟机内存不够时候,下面创建软引用案例:

prime对象是强引用,后面把强引用变成软引用,最后prime强引用至为空,prime对象会被垃圾回收当jvm需要内存时候

弱引用对象会被垃圾回收立即,垃圾回收不会等到需要内存时候,下面弱引用案例:

prime设置为空,prime对象将会被垃圾回收在下个垃圾回收周期中,因为这里没有其他强引用指向它

弱引用作为key存在 WeakHashmap 中

建立缓存保存大量图片对象作为值,图像名称作为key,想用一个合适 Map 来解决这个问题,使用 HashMap 不是好的选择,因为对象值会占用很大内存,垃圾回收时候不会被回收,在不使用时候不会被回收,然而,我们想用 Map 接口

能帮我们自动释放内存当key不被使用时候,刚好 WeakHashMap 具备这个特点,下面是案例:

我们创建 WeakHashMap 实例存储BigImage对象,把BigImage对象作为值和imagename作为key,imageName是弱引用存在 Map 中,接下来设置imageName为空,因此没有更多人指向bigImage对象,WeakHashMap默认会删除key在下个垃圾回收阶段

我也可以调用System.gc()强制触发垃圾回收:

注意imageNameFirst引用至为空,imageNameSecond引用保持不变,垃圾回收之后, map 仅存在imageNameSecond

本文讨论java中引用,理解 WeakHashMap 原理,创建一个简单缓存用WeakhashMap来改变缓存对象

参考地址

四、weakhashmap继承自什么

weakhashmap继承:猜测是因为“xxx”形式时,会首先从字符串静态池中获取。当获取不到时。会new一个放入静态池。调用。

它的生存周期是到方法体结束,在你的输出代码后面。而其他两个都是匿名对象,生存周期是在map的生存周期里,map都回收了自然也被回收了。

UML结构图:

(1) 抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。

(2) 具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。

(3) 享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!

(4) 客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。