参考:http://stackoverflow.com/questions/22890967/java-hashmap-tail-traversing

在看网上HashMap的resize()设计时,提到尾部遍历。
JDK1.7的HashMap在实现resize()时,新table[]的列表采用LIFO方式,即队头插入。这样做的目的是:避免尾部遍历。
参考stackoverflow的讨论,尾部遍历是为了避免在新列表插入数据时,遍历队尾的位置。因为,直接插入的效率更高。
直接采用队头插入,会使得链表数据倒序
例如原来顺序是:
 10  20  30  40
插入顺序如下
10
20  10
30 20 10
40 30 20 10
但对resize()的设计来说,本来就是要创建一个新的table,列表的顺序不是很重要。
但如果要确保插入队尾,还得遍历出链表的队尾位置,然后插入,是一种多余的损耗。
存在问题:
但是采用队头插入的方式,导致了HashMap在“多线程环境下”的死循环问题:http://blog.csdn.net/xiaohui127/article/details/11928865 
JDK1.8的优化
通过增加tail指针,既避免了死循环问题(让数据直接插入到队尾),又避免了尾部遍历。代码如下:
if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;    // JDK1.8改进了rehash算法,扩容时,容量翻倍,新扩容部分,标识为hi,原来old的部分标识为lo
                        Node<K,V> hiHead = null, hiTail = null;    // 声明了队尾和队头指针。
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }

HashMap的尾部遍历问题--Tail Traversing相关推荐

  1. R语言head函数和tail函数获取dataframe、列表list、向量vector的头部和尾部数据:tail提取数据对象的尾部数据、head提取数据对象的头部数据、默认6条数据、自定义设置返回条数

    R语言head函数和tail函数获取dataframe.列表list.向量vector的头部和尾部数据:tail提取数据对象的尾部数据.head提取数据对象的头部数据.默认6条数据.自定义设置返回条数 ...

  2. java学习--基础知识进阶第七天--HashSet集合、HashMap集合(集合遍历)

    今日内容介绍 u  HashSet集合 u  HashMap集合(集合遍历) 第1章 HashSet集合 1.1 Set接口的特点   Set体系的集合: A:存入集合的顺序和取出集合的顺序不一致 B ...

  3. Java - 关于HashMap通过keySet遍历kv的二次调用问题

    Java - 关于HashMap通过keySet遍历kv的二次调用问题 一. HashMap的常规遍历 二. keySet的二次遍历问题 2.1 foreach和迭代器 2.2 问题分析 2.3 总结 ...

  4. hashmap两种遍历总结!

    1.hashmap两种遍历效率1:2----entry----单个遍历两次 public class HashMapTest { public static void main(String[] ar ...

  5. hashmap移除元素_Java HashMap 如何正确遍历并删除元素的方法小结

    (一)HashMap的遍历 HashMap的遍历主要有两种方式: 第一种采用的是foreach模式,适用于不需要修改HashMap内元素的遍历,只需要获取元素的键/值的情况. HashMap myHa ...

  6. HashMap两种遍历数据的方式

    HashMap的遍历有两种方式,一种是entrySet的方式,另外一种是keySet的方式. 第一种利用entrySet的方式: Map map = new HashMap(); Iterator i ...

  7. java 遍历hashmap key_Java5种遍历HashMap数据的写法

    本文介绍了最好的Java5种遍历HashMap数据的写法,分享给大家,也给自己留一个笔记,具体如下: 通过EntrySet的迭代器遍历 Iterator < Entry < Integer ...

  8. HashMap是如何遍历的

    前言 其实用上 JDK1.8 才是近些时日的事,毕竟没有什么新的技术点必须要去用,也懒得去换 JDK 的版本了.这几天在某论坛里看到一个有关于"HashMap如何遍历"的问题,静心 ...

  9. HashMap中的遍历有序性探究

    首先HashMap中的keySet是有序的. 输入代码: @Testpublic void testMapSort(){Map<Integer, Integer> map = new Ha ...

最新文章

  1. 国务院任命!清华、北航分别迎来新任副校长
  2. android 增删改查 源码_学生信息增删改查小程序案例(springboot服务端)
  3. .net core ocelot 获取路由的mothed_Net Core微服务入门全纪录(四)Ocelot网关(上)
  4. edit plus 中文插件_iMindMap手绘思维导图软件中文版
  5. JBoss Forge NetBeans集成–入门
  6. pythonapp自动化_Android App持续集成性能测试:使用Python实现UI自动化
  7. mysql 查看autocommit_手把手教你分析Mysql死锁问题
  8. 历史上的今天:Vue 首次发布;搜狐成立;首个构思集成电路的人出生
  9. “弃用 iOS 后,我的那些 Android 替代方案!”
  10. 想要在Mac 上运行 Windows 程序 不需要虚拟机也可以
  11. 由35国42家电力输送系统运营商组成的欧洲电力协会网络遭攻击
  12. shell多线程执行ping
  13. Java汉字转拼音实现方式
  14. 常用正则表达式匹配Antconc英文句式搭配
  15. 基于UMeng消息推送测试-demo教程(iOS版)
  16. 《德米安》从那以后伤口很痛,但偶尔我会找到钥匙,沉入心底
  17. mysql带中文日期转换_【MySQL】日期时间格式转换_MySQL
  18. js元素选择器-js更具name获取元素中的元素
  19. 实现Python Http 接口测试
  20. mysql cascade 查询_Python全栈 MySQL 数据库 (SQL查询、备份、恢复、授权)

热门文章

  1. 基于FPGA的数据采集—信号产生篇
  2. 计算机ps二级考试试题,2020年3月计算机等级Photoshop考试模拟试题及答案
  3. 大汇总 | 9种基于神经辐射场NeRF的SLAM方法你都知道吗?
  4. 电大网考计算机基础知识,2017年电大计算机网考试题及答案
  5. 新享科技-民营大数据行业领头羊
  6. mac 和 windows excel 格内换行
  7. mySql | Error: ER_DATA_TOO_LONG: Data too long for column 'base_info' at row 1
  8. 51单片机如何跳出wile循环_51单片机(九)汇编指令
  9. 如何对PDF文档进行数字签名
  10. 好多粉数据上报之卧龙搜索ocpc API上报数据