读WeakHashMap源码 博客分类: java集合 java
程序员文章站
2024-03-14 12:41:58
...
//一个基于弱引用的Map对象 //先看构造函数 public WeakHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } public WeakHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public WeakHashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAll(m); } public WeakHashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Initial Capacity: "+ initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load factor: "+ loadFactor); int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; table = newTable(capacity); this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); } //新增元素 public V put(K key, V value) { //将key值为null的转变为对象 Object k = maskNull(key); //计算hash值 int h = hash(k); //获取整个entry在这里面会删掉过期的key Entry<K,V>[] tab = getTable(); int i = indexFor(h, tab.length); for (Entry<K,V> e = tab[i]; e != null; e = e.next) { //如果key已经存在 if (h == e.hash && eq(k, e.get())) { V oldValue = e.value; if (value != oldValue) e.value = value; return oldValue; } } modCount++; Entry<K,V> e = tab[i]; //插入到第一个位置 tab[i] = new Entry<>(k, value, queue, h, e); //扩容 if (++size >= threshold) resize(tab.length * 2); return null; } private static Object maskNull(Object key) { return (key == null) ? NULL_KEY : key; } private static final Object NULL_KEY = new Object(); private Entry<K,V>[] getTable() { expungeStaleEntries(); return table; } //删掉过期的key private void expungeStaleEntries() { for (Object x; (x = queue.poll()) != null; ) { synchronized (queue) { @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>) x; int i = indexFor(e.hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> p = prev; while (p != null) { Entry<K,V> next = p.next; if (p == e) { //此时删除队列的头 if (prev == e) table[i] = next; else prev.next = next; // Must not null out e.next; // stale entries may be in use by a HashIterator //防止内存泄漏 e.value = null; // Help GC size--; break; } prev = p; p = next; } } } } void resize(int newCapacity) { Entry<K,V>[] oldTable = getTable(); int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry<K,V>[] newTable = newTable(newCapacity); boolean oldAltHashing = useAltHashing; useAltHashing |= sun.misc.VM.isBooted() && (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean rehash = oldAltHashing ^ useAltHashing; transfer(oldTable, newTable, rehash); table = newTable; if (size >= threshold / 2) { threshold = (int)(newCapacity * loadFactor); } else { expungeStaleEntries(); transfer(newTable, oldTable, false); table = oldTable; } } //构造新的entry private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest, boolean rehash) { for (int j = 0; j < src.length; ++j) { Entry<K,V> e = src[j]; src[j] = null; while (e != null) { Entry<K,V> next = e.next; Object key = e.get(); if (key == null) { e.next = null; // Help GC e.value = null; // " " size--; } else { if (rehash) { e.hash = hash(key); } int i = indexFor(e.hash, dest.length); e.next = dest[i]; dest[i] = e; } e = next; } } } /** 插入元素的过程就是上面这样,现在的问题是自动回收怎么回收?*/ //看插入时候的这句代码 tab[i] = new Entry<>(k, value, queue, h, e); //然后就看到这个entry private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { V value; 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; } //然后就是 public abstract class Reference<T> //里面有一个线程 private static class ReferenceHandler extends Thread { ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { //由虚拟机赋值 r = pending; Reference rn = r.next; pending = (rn == r) ? null : rn; r.next = r; } else { try { lock.wait(); } catch (InterruptedException x) { } continue; } } // Fast path for cleaners if (r instanceof Cleaner) { ((Cleaner)r).clean(); continue; } ReferenceQueue q = r.queue; //入队 if (q != ReferenceQueue.NULL) q.enqueue(r); } } } boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ synchronized (r) { if (r.queue == ENQUEUED) return false; synchronized (lock) { r.queue = ENQUEUED; r.next = (head == null) ? r : head; head = r; queueLength++; if (r instanceof FinalReference) { sun.misc.VM.addFinalRefCount(1); } lock.notifyAll(); return true; } } } /** 总结:每次在put一个元素的时候,首先会从ReferenceQueue中找出已经过期的键然后删除掉。 然后每次在新建的时候entry的时候后台会通过ThreadGroup来管理一组线程。这组线程主要是 jvm给Reference赋值已经过期的key。然后加入到ReferenceQueue的队列中。 */ public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0) return; //先计算是否需要扩容 提升效率 if (numKeysToBeAdded > threshold) { int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; while (newCapacity < targetCapacity) newCapacity <<= 1; if (newCapacity > table.length) resize(newCapacity); } for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); } //根据键获取值 public V get(Object key) { Object k = maskNull(key); int h = hash(k); Entry<K,V>[] tab = getTable(); int index = indexFor(h, tab.length); Entry<K,V> e = tab[index]; while (e != null) { if (e.hash == h && eq(k, e.get())) return e.value; e = e.next; } return null; } //返回长度 public int size() { if (size == 0) return 0; expungeStaleEntries(); return size; } //整个map是否为空 public boolean isEmpty() { return size() == 0; } //是否包含某个键 public boolean containsKey(Object key) { return getEntry(key) != null; } Entry<K,V> getEntry(Object key) { Object k = maskNull(key); int h = hash(k); Entry<K,V>[] tab = getTable(); int index = indexFor(h, tab.length); Entry<K,V> e = tab[index]; while (e != null && !(e.hash == h && eq(k, e.get()))) e = e.next; return e; } //根据key删除 public V remove(Object key) { Object k = maskNull(key); int h = hash(k); Entry<K,V>[] tab = getTable(); int i = indexFor(h, tab.length); Entry<K,V> prev = tab[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; if (h == e.hash && eq(k, e.get())) { modCount++; size--; if (prev == e) tab[i] = next; else prev.next = next; return e.value; } prev = e; e = next; } return null; } //删除entry boolean removeMapping(Object o) { if (!(o instanceof Map.Entry)) return false; Entry<K,V>[] tab = getTable(); Map.Entry<?,?> entry = (Map.Entry<?,?>)o; Object k = maskNull(entry.getKey()); int h = hash(k); int i = indexFor(h, tab.length); Entry<K,V> prev = tab[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; if (h == e.hash && e.equals(entry)) { modCount++; size--; if (prev == e) tab[i] = next; else prev.next = next; return true; } prev = e; e = next; } return false; } //清空 public void clear() { while (queue.poll() != null) ; modCount++; Arrays.fill(table, null); size = 0; while (queue.poll() != null) ; } //是否包含某个值 public boolean containsValue(Object value) { if (value==null) return containsNullValue(); Entry<K,V>[] tab = getTable(); for (int i = tab.length; i-- > 0;) for (Entry<K,V> e = tab[i]; e != null; e = e.next) if (value.equals(e.value)) return true; return false; }
推荐阅读
-
读ExecutorCompletionService源码 博客分类: java多线程 java
-
读WeakHashMap源码 博客分类: java集合 java
-
读WeakHashMap源码 博客分类: java集合 java
-
读IdentityHashMap源码 博客分类: java集合 java
-
读ExecutorCompletionService源码 博客分类: java多线程 java
-
读EnumMap源码 博客分类: java集合 java
-
读EnumSet源码 博客分类: java集合 java
-
读Stack源码 博客分类: java集合 java
-
读ThreadLocal源代码 博客分类: java多线程 java
-
读Collections源码 博客分类: java集合 java