zoukankan      html  css  js  c++  java
  • HashMap&HashTable&ConcurrentHashMap

    当考察数据结构时,面试官一开始会问HashMap的实现原理,扩容等问题,当你说出HashMap并非线程安全之后,会让你自己引出ConcurrentHashMap,接着就可能开始如下的对话。

    场景对话: 

    面试官:简单问你下Java中的一种数据结构HashMap(一听到这个问题就知道并不简单了),你能说说分析下他的put操作吗?

    我:balabala如下图

    面试官:你能谈谈他的容量问题吗? 

    我:hashmap的初始容量是16,内部有一个负载因子初始为0.75,当数组中元素达到初始值*负载因子时,就会进行扩容。方法是使用一个新的数组,数组大小为原来的两倍。当然负载因子的大小是可调的,当我们有足够的内存而且非常看重时间的时候,可以将负载因子减小一点,反之可以增加负载因子。

    面试官:那为什么初始容量是16?

    我:在计算数组索引位置的时候采用两次hash第一次是调用hashcode()方法得到h,第二次是用h&(length-1)

    当length为偶数的时候(length-1)得到的二进制的最后一位为1,&运算后即能得到奇数又能得到偶数。而length为奇数仅仅能得到偶数,这样浪费了一般空间。

    当length为合数[二的幂方]时h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率,这样保证了索引能均匀分布。

    综合来说取16是为了增加桶数组的利用率和减少hash碰撞。

    面试官:在多线程的环境下,使用hashmap会出现什么情况,怎么解决呢?

    我:hashmap是非线程安全的,可以使用ConcurrentHashMap。

    面试官:谈谈ConcurrentHashMap实现原理。

    我:@#¥@@基于分段锁的%%¥#@#¥,但是1.8之后做了一些改进。

    面试官:什么改进?

    我:改进一:取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。

    改进二:将原先table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构。对于hash表来说,最核心的能力在于将key hash之后能均匀的分布在数组中。如果hash之后散列的很均匀,那么table数组中的每个链表长度主要为0或者1。但实际情况并非总是如此理想,虽然ConcurrentHashMap类默认的加载因子为0.75,但是在数据量过大或者运气不佳的情况下,还是会存在一些链表长度过长的情况,如果还是采用单向列表方式,那么查询某个节点的时间复杂度为O(n);因此,对于个数超过8(默认值)的列表,jdk1.8中采用了红黑树的结构,那么查询的时间复杂度可以降低到O(logN),可以改进性能[主要是get的性能]。

    面试官:能讲下红黑树的概念吗?

    我:红黑树是一种二叉树,并且是平衡……%……¥……,

    面试官:能讲下红黑树的。。。。。

    我:打住,别问了,红黑树我只知道他是二叉树,比其他树多一个属性,其他的我都不知道

    面试官:好的,那换个,你知道它的size方法是如何实现的么?

    我:size方法?是想要得到Map中的元素个数么?

    面试官:对的....

    我:我记得好像size方法返回是不准确的,平时也不会用到这个方法...

    面试官:如果你觉得size方法返回值不准确,那如果让你自己实现,你觉得应该怎么实现呢?

    我:...@#¥@@...两眼一黑

    我:等等,让我想想.....应该可以用AtomicInteger变量进行记录...嗯,对的,每次插入或删除的时候,操作这个变量,我得意的一笑...

    面试官:哦,是么,那如果我觉得这个AtomicInteger这个变量性能不好,还能再优化么?

    我:懵逼脸...(当时居然把volitile变量给忘记了)...好像没有了,我想不出来了...

    面试官:哦,那回头你再看看源码吧,jdk中已经实现了...

    我:哦,是么....

    面试官:那今天的面试到此结束,我们后面会通知你。

    我:..................

  • 相关阅读:
    数组,一维,二维,多维
    类函数:string、math
    while和for的内嵌
    循环语言(for)
    选择语言之switch case
    程序语言
    语言、数据和运算符
    原理之一,进制转换
    HTML第一部分
    结构体共用变量 递归
  • 原文地址:https://www.cnblogs.com/WegYcx/p/7495820.html
Copyright © 2011-2022 走看看