【java源码一带一路系列】之LinkedHashMap.afterNodeAccess()
字数统计:
732字
|
阅读时长:
3分钟
2017.05.21
Chen hongen
后端
本文以jdk1.8中LinkedHashMap.afterNodeAccess()方法为切入点,分析其中难理解、有价值的源码片段(类似源码查看是ctrl+鼠标左键的过程)。观光线路图:afterNodeAccess() –> afterNodeInsertion() –> removeEldestEntry() –> afterNodeRemoval() –> internalWriteEntries() …
☞ afterNodeAccess()
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 35 36 37 38 39 40 41 42 43 44
| void afterNodeAccess(Node<K,V> e) { LinkedHashMap.Entry<K,V> last; if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.after = null; if (b == null) head = a; else b.after = a; if (a != null) a.before = b; else last = b; if (last == null) head = p; else { p.before = last; last.after = p; } tail = p; ++modCount; } } * The head (eldest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> head; * The tail (youngest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> tail; * The iteration ordering method for this linked hash map: <tt>true</tt> * for access-order, <tt>false</tt> for insertion-order. * * @serial */ final boolean accessOrder;
|
上回在HashMap.afterNodeAccess()中说道,“是为LinkedHashMap留的后路”。如今行至于此,当观赏一方。首先需要了解的是LinkedHashMap相比HashMap多了有序性,由双向链表(before,after)实现。源码出现了一些全局变量:
accessOrder:true:按访问顺序排序(LRU),false:按插入顺序排序;
head、tail:存放链表首尾;
可见仅有accessOrder为true时,且访问节点不等于尾节点时,该方法才有意义。通过before、after重定向,将新访问节点链接为链表尾节点。
☞ afterNodeInsertion()
1 2 3 4 5 6 7 8 9 10 11
| void afterNodeInsertion(boolean evict) { 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; }
|
细心的你也花现了吧。afterNodeInsertion()由于removeEldestEntry()所返回的false无执行意义。也就意味着如果想要让它有意义必须重写removeEldestEntry()。
如,使用LinkedHashMap实现一个简单的LRU(Least Recently Used)Cache。那么就应该重写removeEldestEntry(),当超出缓存容器大小时移除最老的首节点(这里不考虑并发问题,如下):
1 2 3 4
| @Override public boolean removeEldestEntry(Map.Entry<K, V> eldest){ return size() > capacity; }
|
☞ afterNodeRemoval()
1 2 3 4 5 6 7 8 9 10 11 12 13
| void afterNodeRemoval(Node<K,V> e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.before = p.after = null; if (b == null) head = a; else b.after = a; if (a == null) tail = b; else a.before = b; }
|
afterNodeRemoval()方法相对简单,就是在删除后处理其对应链表前后关系(刨掉一截)。
☞ internalWriteEntries()
LinkedHashMap源码阅读总体门槛相对而言比HashMap,毕竟大多数底层put,get都由HashMap实现了。internalWriteEntries()相对来说比较突兀,如果你知道它在哪里起着什么样神秘的作用请在评论里告诉在下吧。[比心❤]
1 2 3 4 5 6
| void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) { s.writeObject(e.key); s.writeObject(e.value); } }
|
可通过这篇文章理解创建一个LinkedHashMap实例过程(图):
Java_LinkedHashMap工作原理 2017-05-04;