那些年被面试官按在地上摩擦系列一(基于hashMap系列)
那些年被面试官按在地上摩擦面试题系列一
-
HashMap底层原理
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来储存值对象。当获取对象时,通过hash值找到bucket,通过键对象的equals()方法找到正确的键值对返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。当两个不同的键对象的hashcode相同时, 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。 (jdk1.7以后当bucket位置对应链表长度为8后建以红黑树来进行存储。 面试官可能会追问 链表与红黑树相关问题,这个等后面再说), (此时面试官会心一笑,小伙子不错!) -
HashMap与HashTable有和不同?
HashMap与HashTable不用之处主要在三点:线程安全性,键值是否为空,内部迭代器
HashMap是非线程安全的,HashTable是线程安全的内部方法上使用了synchronization来保证线程安全。因此在单线程情况下HashTable速度要低于HashMape
HashMap中key-value都可以存储为null,而HashTable则不允许为null
HashMap的迭代器(Iterator)是fail-fast迭代器,当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步
(接下来会接问那么我们使用怎么使用线程安全的map那??) -
Hashtable和ConcurrentHashMap如何实现线程安全
Hashtable使用synchronization来保证线程安全,因此操作时会锁住了整个hash表,性能较差。而ConcurrentHashMap则使用分段,来锁住不同区域,ConcurrentHashMap将hash片段分为了16个区域,只针对此指定段hash上锁但有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁. -
HashMap的resize方法中尾部遍历出现死循环问题 Tail Traversing (多线程)
建议看此链接:https://www.cnblogs.com/gxyandwmm/p/9537669.html
—后续会继续录入关于hashmap系列题