8. LinkedHashMap source code analysis

1. The data structure
LinkedHashMap inherits from HashMap. The underlying data structure is the same as HashMap and has all the characteristics of HashMap. The difference is that LinkedHashMap has added "Access in order of insertion" and "Remove the least access element strategy".
Source code

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
    
    
	//链表头
	transient LinkedHashMap.Entry<K,V> head;
	 
	//链表尾
	transient LinkedHashMap.Entry<K,V> tail;
	 
	//继承Node,为数组的每个元素增加了before和after属性
	static class Entry<K,V> extends HashMap.Node<K,V> {
    
    
	    Entry<K,V> before, after;
	    Entry(int hash, K key, V value, Node<K,V> next) {
    
    
	        super(hash, key, value, next);
	    }
	}
	 
	/**
     * 控制两种访问模式的字段,默认为false
     * true表示按照访问顺序把经常访问的key放到队尾
     * false表示按照插入顺序访问
     */
	final boolean accessOrder;
}

Source code analysis
As can be seen from the new attributes of the above Map, the data structure of LinkedHashMap is very similar to replacing the elements of LinkedList with the Node of HashMap. It is precisely because of the addition of these structures that Map elements can be connected in series to form a linked list. The linked list can guarantee the order and maintain the order of element insertion.

2.
Newly added LinkedHashMap through the newNode/newTreeNode method to add nodes, the following uses newNode as an example to analyze the source code, the specific source code is as follows.

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
    
    
	Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    
    
		//新增节点
        LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
        //追加到链表的尾部
        linkNodeLast(p);
        return p;
    }

	private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    
    
        LinkedHashMap.Entry<K,V> last = tail;
        //新增节点等于尾节点
        tail = p;
        //last为空,说明链表为空,首尾节点相等
        if (last == null)
            head = p;
        //链表有数据,直接建立新增节点和上个尾节点之间的前后关系
        else {
    
    
            p.before = last;
            last.after = p;
        }
    }
}

Source code analysis

  1. When LinkedHashMap is initialized, accessOrder is false, and access will be provided in the order of insertion. The insert method uses the put method of the parent class HashMap, but the put method is overwritten, and the newNode/newTreeNode and afterNodeAccess methods are called during execution.
  2. LinkedHashMap adds before and after attributes to each node by adding a head node and a tail node. Each time a new node is added, the node is added to the tail node, so that it can be ensured that the new node is inserted into the linked list in order.

3. Access
LinkedHashMap is mainly accessed through an iterator. When the iterator is initialized, it is accessed from the head node by default. During the iteration, you can continue to access the after node of the current node. The specific source code of the iterator is as follows.

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
    
    
	abstract class LinkedHashIterator {
    
    
		LinkedHashMap.Entry<K,V> next;
		LinkedHashMap.Entry<K,V> current;
		int expectedModCount;
		//初始化时默认从头节点开始访问
		LinkedHashIterator() {
    
    
		   //头节点作为第一个访问的节点
		   next = head;
		   expectedModCount = modCount;
		   current = null;
		}
		
		final LinkedHashMap.Entry<K,V> nextNode() {
    
    
		   LinkedHashMap.Entry<K,V> e = next;
		   //校验
		   if (modCount != expectedModCount)
		       throw new ConcurrentModificationException();
		   if (e == null)
		       throw new NoSuchElementException();
		   current = e;
		   //通过链表的after结构,找到下一个迭代的节点
		   next = e.after;
		   return e;
		}
	}
}

Source code analysis

  1. LinkedHashMap only provides one-way access, that is, access is performed from start to end in the order of insertion, and two-way access cannot be performed like LinkedList.
  2. When adding a new node, the insertion order between the elements has been maintained, so when iteratively visits, you only need to keep visiting the next node of the current node.

4. Access to the least delete strategy
This strategy is also called LRU (Least recently used, least recently used), that is, frequently accessed elements will be appended to the end of the team, so that the data that is not frequently accessed will naturally be close to the head of the team, and then deleted by setting Strategy (such as when the number of Map elements is greater than a certain threshold), delete the head node, the specific source code is as follows.

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
    
    
	public V get(Object key) {
    
    
	   Node<K,V> e;
	   //调用HashMap的get方法
	   if ((e = getNode(hash(key), key)) == null)
	       return null;
	   //如果设置了LRU策略,就把当前key移动到队尾
	   if (accessOrder)
	       afterNodeAccess(e);
	   return e.value;
	}
	
	//删除很少被访问的元素 
	void afterNodeInsertion(boolean evict) {
    
    
	   //得到元素头节点
	   LinkedHashMap.Entry<K,V> first;
	   //removeEldestEntry来控制删除策略,如果队列不为空,并且删除策略允许删除的情况下,删除头节点
	   if (evict && (first = head) != null && removeEldestEntry(first)) {
    
    
	       K key = first.key;
	       //删除头节点
	       removeNode(hash(key), key, null, false, true);
	   }
	}
}

Source code analysis

  1. Move the currently visited node to the end of the queue through the afterNodeAccess method, not only the get method, but also when the getOrDefault, compute, computeIfAbsent, computeIfPresent, and merge methods are executed. After constantly moving frequently visited nodes to the end of the team, the nodes close to the head of the team are naturally the elements that are rarely visited.
  2. LinkedHashMap itself does not implement the put method. It calls the put method of HashMap, but LinkedHashMap implements the afterNodeInsertion method in the put method, which implements the delete operation.

Guess you like

Origin blog.csdn.net/Jgx1214/article/details/109096664