专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  今年的行情,还得是Java! ·  昨天  
Java编程精选  ·  SpringBoot实现各种参数校验,写得太 ... ·  3 天前  
Java编程精选  ·  SpringBoot 动态加载jar包,动态配置 ·  昨天  
芋道源码  ·  今年后端这工资是认真的吗? ·  2 天前  
Java知音  ·  让数据传输更优雅:SpringBoot前后端 ... ·  6 天前  
51好读  ›  专栏  ›  ImportNew

浅谈 WeakHashMap

ImportNew  · 公众号  · Java  · 2017-04-16 12:01

正文

(点击上方公众号,可快速关注)


来源:CarpenterLee,

www.cnblogs.com/CarpenterLee/p/5544598.html

如有好文章投稿,请点击 → 这里了解详情


Java WeakHashMap 到底Weak在哪里,它真的很弱吗?WeakHashMap 的适用场景是什么,使用时需要注意些什么?弱引用和强引用对Java GC有什么不同影响?本文将给出清晰而简洁的介绍。


总体介绍


在Java集合框架系列文章的最后,笔者打算介绍一个特殊的成员:WeakHashMap,从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。


更直观的说,当使用 WeakHashMap 时,即使没有显示的添加或删除任何元素,也可能发生如下情况:


  • 调用两次size()方法返回不同的值;

  • 两次调用isEmpty()方法,第一次返回false,第二次返回true;

  • 两次调用containsKey()方法,第一次返回true,第二次返回false,尽管两次使用的是同一个key;

  • 两次调用get()方法,第一次返回一个value,第二次返回null,尽管两次使用的是同一个对象。


遇到这么奇葩的现象,你是不是觉得使用者一定会疯掉?其实不然,WeekHashMap 的这个特点特别适用于需要缓存的场景。在缓存场景下,由于内存是有限的,不能缓存所有对象;对象缓存命中可以提高系统效率,但缓存MISS也不会造成错误,因为可以通过计算重新得到。


要明白 WeekHashMap 的工作原理,还需要引入一个概念:弱引用(WeakReference)。我们都知道Java中内存是通过GC自动管理的,GC会在程序运行过程中自动判断哪些对象是可以被回收的,并在合适的时机进行内存释放。GC判断某个对象是否可被回收的依据是,是否有有效的引用指向该对象。如果没有有效引用指向该对象(基本意味着不存在访问该对象的方式),那么该对象就是可回收的。这里的“有效引用”并不包括弱引用。也就是说,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收。


WeakHashMap 内部是通过弱引用来管理entry的,弱引用的特性对应到 WeakHashMap 上意味着什么呢?将一对key, value放入到 WeakHashMap 里并不能避免该key值被GC回收,除非在 WeakHashMap 之外还有对该key的强引用。


关于强引用,弱引用等概念以后再具体讲解,这里只需要知道Java中引用也是分种类的,并且不同种类的引用对GC的影响不同就够了。


具体实现


WeakHashMap的存储结构类似于HashMap,读者可自行参考前文(https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/6-HashSet%20and%20HashMap.md),这里不再赘述。


关于强弱引用的管理方式,博主将会另开专题单独讲解。


Weak HashSet?


如果你看过前几篇关于 Map 和 Set 的讲解,一定会问:既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是没有:( 。不过Java Collections工具类给出了解决方案,Collections.newSetFromMap(Map map)方法可以将任何 Map包装成一个Set。通过如下方式可以快速得到一个 Weak HashSet:


// 将WeakHashMap包装成一个Set

Set weakHashSet = Collections.newSetFromMap(

        new WeakHashMap());


不出你所料,newSetFromMap()方法只是对传入的 Map做了简单包装:


// Collections.newSetFromMap()用于将任何Map包装成一个Set

public static Set newSetFromMap(Map map) {

    return new SetFromMap<>(map);

}

 

private static class SetFromMap extends AbstractSet

    implements Set, Serializable

{

    private final Map m;  // The backing map

    private transient Set s;       // Its keySet

    SetFromMap(Map map) {

        if (!map.isEmpty())

            throw new IllegalArgumentException("Map is non-empty");

        m = map;

        s = map.keySet();

    }

    public void clear()               {        m.clear(); }

    public int size()                 { return m.size(); }

    public boolean isEmpty()          { return m.isEmpty(); }

    public boolean contains(Object o) { return m.containsKey(o); }

    public boolean remove(Object o)   { return m.remove(o) != null; }

    public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }

    public Iterator iterator()     { return s.iterator(); }

    public Object[] toArray()         { return s.toArray(); }

    public T[] toArray(T[] a)     { return s.toArray(a); }

    public String toString()          { return s.toString(); }

    public int hashCode()             { return s.hashCode(); }

    public boolean equals(Object o)   { return o == this || s.equals(o); }

    public boolean containsAll(Collection> c) {return s.containsAll(c);}

    public boolean removeAll(Collection> c)   {return s.removeAll(c);}

    public boolean retainAll(Collection> c)   {return s.retainAll(c);}

    // addAll is the only inherited implementation

    ......

}


结语


至此深入《 Java集合框架(Java Collections Framework Internals)系列 》(https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/0-Introduction.md)已经全部讲解完毕,希望这几篇简短的博文能够帮助各位读者对Java容器框架建立基本的理解。通过这里可以返回《 本系列文章目录 》(https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/0-Introduction.md)。


如果对各位有哪怕些微的帮助,博主将感到非常高兴!如果博文中有任何的纰漏和谬误,欢迎各位博友指正。


本文GitHub地址:

https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/9-WeakHashMap.md


看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能