一、概述

LinkedHashMap继承自HashMap,是Map接口的一个具体实现,它是有序的,可以按照插入顺序先后和访问时间先后进行排序,选择哪种排序方式取决于在新建LinkedHashMap的时候是否指定了accessOrder为true。如果不指定,accessOrder默认为false,LinkedHashMap会按照插入顺序进行排序;入股指定为true,则会按照LRU算法将最少访问的元素排在前面。

LinkedHashMap中的removeEldestEntry(Map.Entry)方法默认返回false,如果重写,如:

private static final int MAX_ENTRIES = 100;

protected boolean removeEldestEntry(Map.Entry eldest) {

return size() > MAX_ENTRIES;

}

,则当节点达到100,再插入新节点就会删除过时的链表头部的节点。

LinkedHashMap提供了所有可选的Map操作,并允许插入null。因为要多维护一个链表,其性能可能略低于HashMap。但是,有一个例外:对LinkedHashMap的集合视图的迭代需要时间与map大小成正比,而不管其容量。 HashMap上的迭代可能会花销更大,需要的时间与其容量成正比。也就是说capacity 的大小对其性能影响没有对HashMap的大。

LinkedHashMap的实现是非同步的。当涉及到多个线程访问并且有线程改变其结构时,必须在外部进行同步。通常对使用map的对象进行同步来完成同步操作。如果不存在这样的对象,则应该使用Collections.synchronizedMap方法包裹该map。而且最好在创建时包裹,以防止不同步访问:

Map m = Collections.synchronizedMap(new LinkedHashMap(...));

这里,需要注意的是map节点的值改变不会导致结构改变,结构改变是指添加、删除节点或者修改顺序引起的改变。

LinkedHashMap继承了HashMap的fail-fast(快速失败)机制,该机制的实现是通过一个modCount变量来记录修改次数,在每次调用会导致LinkedHashMap结构改变的方法的时候就比较下理论上的修改次数和当前修改次数的值。如果相等则允许操作,并将modCount加1,如果不相等则抛出ConcurrentModificationException异常。这种机制只能用来检测错误,无法保证一定起效。

二、结构

LinkedHashMap之所以能够进行排序,是因为它在HashMap的“数组+链表”的结构上还维护了一个双向链表,其节点结构可以参考如下的图(这里重点关注before和after节点):

(图1)

整体结构可以参考如下的图(图上半部分的“数组+链表”结构继承自HashMap,绿色的箭头代表图1中的next,排序的实现主要通过下面的双向链表):

(图2来自:http://blog.csdn.net/luanlouis/article/details/43017071

三、源码分析

构造函数:

这里注意到第四个构造函数,如果指定第三个参数为true会开启按访问时间排序。另外几个构造函数都有设置accessOrder = false。

属性:

accessOrder已经说明过了。剩下的,head代表的是双向链表的头部,表示最久未被访问的节点。tail代表的是双向链表的尾部,表示最近一次访问的节点。

方法:

这里可以重点看下afterNodeAccess方法,调用put,putAll,putIfAbsent,get,getOrDefault,compute,computeIfAbsent,computeIfPresent或merge方法时都将调用该方法。而调用该方法时,如果accessOrder为true,且当前操作的节点在方法调用后存在,则会移动当前操作的节点至双向链表尾部。

void afterNodeAccess(Node<K,V> e) { // move node to last
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;
}
}

其他方法介绍可参考:

http://blog.csdn.net/u014634338/article/details/78494051

四、总结

LinkedHashMap继承于 HashMap,相当于在HashMap的基础上添加了顺序访问的功能,而方法的操作也是基于HashMap之上,增加了对提供顺序访问功能的双向链表的维护。

LinkedHashMap学习的更多相关文章

  1. Java学习之LinkedHashMap学习总结

    前言: 在学习LRU算法的时候,看到LruCache源码实现是基于LinkedHashMap,今天学习一下LinkedHashMap的好处以及如何实现lru缓存机制的. 需求背景: LRU这个算法就是 ...

  2. Java LinkedHashMap学习

    以前一直使用HashMap,今天学习一下LinkedHashMap JavaDoc 注解: Hash table and linked list implementation of the Map i ...

  3. HashMap,TreeMap,LinkedHashMap学习

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复.Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快 ...

  4. java集合类学习笔记之LinkedHashMap

    1.简述 LinkedHashMap是HashMap的子类,他们最大的不同是,HashMap内部维护的是一个单向的链表数组,而LinkedHashMap内部维护的是一个双向的链表数组.HashMap是 ...

  5. JDK源码学习笔记——LinkedHashMap

    HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...

  6. 【Java学习笔记】HashMap子接口---LinkedHashMap

    特点: 存入元素的顺序   与   取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...

  7. LinkedHashMap源码学习

    描述 可以按照添加元素的顺序对元素进行迭代的HashMap的子类. 注意,上面说的是加元素的顺序.也就是说,更新元素时,是不会影响遍历结构的的.除非设置参数accessOrder为true,将更新元素 ...

  8. Java集合学习(5):LinkedHashMap

    一.概述 HashMap是无序的,HashMap在put的时候是根据key的hashcode进行hash然后放入对应的地方.所以在按照一定顺序put进HashMap中,然后遍历出HashMap的顺序跟 ...

  9. 学习JDK1.8集合源码之--LinkedHashMap

    1. LinkedHashMap简介 LinkedHashMap继承自HashMap,实现了Map接口. LinkedHashMap是HashMap的一种有序实现(多态,HashMap的有序态),可以 ...

随机推荐

  1. python学习之多线程(二)

    使用multiprocessing 使用multiprocessing.dummy 单使用multiprocessing模块的指的是多进程,使用multiprocessing.dummy则表示使用的是 ...

  2. Python递归输出字典所有不同深度的路径

    应用场景 假设有这样一个字典结构test_dict = {'a':{'b':{'c':1}},'d':2},test_dict其实可以看作是一种树状结构,其中每个叶子节点深度不一定相同,如果我们希望输 ...

  3. (转)Java获取CLASSPATH路径

    ClassLoader提供了两个方法用于从装载的类路径中取得资源: public URL getResource(String name); public InputStream getResourc ...

  4. Git与github常用命令

    Git项目与github建立联系 首先,需要在github上建立一个repository mkdir github-project cd github-project git init 此时githu ...

  5. vb编写串口调试程序

    sub是子模块,可以调用但是没有返回值,function是有返回值的. public sub 可以在其它form里调用,而private sub 只能在当前form里调用. vb里的if else , ...

  6. BZOJ3590 [Snoi2013]Quare

    题意 4.20四川芦山地震发生后,抗震救灾委员会接到一个紧急任务,四川省给该委员会发了一份地图,这份地图给出了该省一些城市的情况:任两个城市是用一条或多条公路连接起来的,也可以没有公路连接,但是每个城 ...

  7. 在linux安装redis单机和集群后,如何在windows上使用redis客户端或者java代码访问错误的原因很简单,就是没有连接上redis服务,由于redis采用的安全策略,默认会只准许本地访问。需要通过简单配置,完成允许外网访问。

    这几天在学习在linux上搭建服务器的工作,可谓历经艰辛.可喜最后收获也不少. 这次是在linux上搭建redis服务器后从windows上缺无法访问,连接不上. 仔细回忆以前搭建nginx和ftp的 ...

  8. EditPlus 3.41 p1115 0728注册码

    EditPlus (2012-7-28 epp341p1115_0728) 注册码: 注册名:Free User 注册码:6AC8D-784D8-DDZ95-B8W3A-45TFA 注册名:Www.S ...

  9. 一些IPC常用头文件

    //my_err.h#include <errno.h> /* for definition of errno */ #include <stdarg.h> /* ISO C ...

  10. Docker安装ShowDoc

    ShowDoc就是一个非常适合IT团队的在线文档分享工具,它可以加快团队之间沟通的效率. 一.下载showDoc资源 打开 https://github.com/star7th/showdoc 复制其 ...