浅谈WeakHashMap
Java?WeakHashMap?到底Weak在哪里,它真的很弱嗎?WeakHashMap?的適用場景是什么,使用時(shí)需要注意些什么?弱引用和強(qiáng)引用對Java GC有什么不同影響?本文將給出清晰而簡潔的介紹。
總體介紹
在Java集合框架系列文章的最后,筆者打算介紹一個(gè)特殊的成員:WeakHashMap,從名字可以看出它是某種?Map。它的特殊之處在于?WeakHashMap?里的entry可能會(huì)被GC自動(dòng)刪除,即使程序員沒有調(diào)用remove()或者clear()方法。
更直觀的說,當(dāng)使用?WeakHashMap?時(shí),即使沒有顯示的添加或刪除任何元素,也可能發(fā)生如下情況:
- 調(diào)用兩次size()方法返回不同的值;
- 兩次調(diào)用isEmpty()方法,第一次返回false,第二次返回true;
- 兩次調(diào)用containsKey()方法,第一次返回true,第二次返回false,盡管兩次使用的是同一個(gè)key;
- 兩次調(diào)用get()方法,第一次返回一個(gè)value,第二次返回null,盡管兩次使用的是同一個(gè)對象。
遇到這么奇葩的現(xiàn)象,你是不是覺得使用者一定會(huì)瘋掉?其實(shí)不然,WeekHashMap?的這個(gè)特點(diǎn)特別適用于需要緩存的場景。在緩存場景下,由于內(nèi)存是有限的,不能緩存所有對象;對象緩存命中可以提高系統(tǒng)效率,但緩存MISS也不會(huì)造成錯(cuò)誤,因?yàn)榭梢酝ㄟ^計(jì)算重新得到。
要明白?WeekHashMap?的工作原理,還需要引入一個(gè)概念:弱引用(WeakReference)。我們都知道Java中內(nèi)存是通過GC自動(dòng)管理的,GC會(huì)在程序運(yùn)行過程中自動(dòng)判斷哪些對象是可以被回收的,并在合適的時(shí)機(jī)進(jìn)行內(nèi)存釋放。GC判斷某個(gè)對象是否可被回收的依據(jù)是,是否有有效的引用指向該對象。如果沒有有效引用指向該對象(基本意味著不存在訪問該對象的方式),那么該對象就是可回收的。這里的“有效引用”并不包括弱引用。也就是說,雖然弱引用可以用來訪問對象,但進(jìn)行垃圾回收時(shí)弱引用并不會(huì)被考慮在內(nèi),僅有弱引用指向的對象仍然會(huì)被GC回收。
WeakHashMap?內(nèi)部是通過弱引用來管理entry的,弱引用的特性對應(yīng)到?WeakHashMap?上意味著什么呢?將一對key, value放入到?WeakHashMap?里并不能避免該key值被GC回收,除非在?WeakHashMap?之外還有對該key的強(qiáng)引用。
關(guān)于強(qiáng)引用,弱引用等概念以后再具體講解,這里只需要知道Java中引用也是分種類的,并且不同種類的引用對GC的影響不同就夠了。
具體實(shí)現(xiàn)
WeakHashMap的存儲(chǔ)結(jié)構(gòu)類似于HashMap,讀者可自行參考前文,這里不再贅述。
關(guān)于強(qiáng)弱引用的管理方式,博主將會(huì)另開專題單獨(dú)講解。
Weak HashSet?
如果你看過前幾篇關(guān)于?Map?和?Set?的講解,一定會(huì)問:既然有?WeekHashMap,是否有?WeekHashSet?呢?答案是沒有:( 。不過Java?Collections工具類給出了解決方案,Collections.newSetFromMap(Map<E,Boolean> map)方法可以將任何?Map包裝成一個(gè)Set。通過如下方式可以快速得到一個(gè)?Weak HashSet:
| 1 2 3 | // 將WeakHashMap包裝成一個(gè)Set Set<Object> weakHashSet = Collections.newSetFromMap( ????????new WeakHashMap<Object, Boolean>()); |
不出你所料,newSetFromMap()方法只是對傳入的?Map做了簡單包裝:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // Collections.newSetFromMap()用于將任何Map包裝成一個(gè)Set public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) { ????return new SetFromMap<>(map); } private static class SetFromMap<E> extends AbstractSet<E> ????implements Set<E>, Serializable { ????private final Map<E, Boolean> m;? // The backing map ????private transient Set<E> s;?????? // Its keySet ????SetFromMap(Map<E, Boolean> 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<E> iterator()???? { return s.iterator(); } ????public Object[] toArray()???????? { return s.toArray(); } ????public <T> 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 ????...... } |
結(jié)語
至此深入Java集合框架(Java Collections Framework Internals)系列已經(jīng)全部講解完畢,希望這幾篇簡短的博文能夠幫助各位讀者對Java容器框架建立基本的理解。通過這里可以返回本系列文章目錄。
如果對各位有哪怕些微的幫助,博主將感到非常高興!如果博文中有任何的紕漏和謬誤,歡迎各位博友指正。
本文GitHub地址
原文出處:?CarpenterLee
from:?http://www.importnew.com/23182.html
總結(jié)
以上是生活随笔為你收集整理的浅谈WeakHashMap的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDK动态代理详解
- 下一篇: JVM初探——使用堆外内存减少Full