TreeSet、HashSet、LinkedHashSet的底层实现以及之间的区别;
HashSet和HashMap都是基于hash表(数组+链表)实现的,HashSet是基于HashMap实现
1、HashMap是key - value的存储方式;HashSet只存储元素对象
2、HashMap允许null值,key不重复,value可以重复;HashSet不允许重复,无序性
利用HashMap 的containsKey()方法,将对象元素作为key传入,然后就可以确保该元素在HashSet中的不重复性,另外根据add方法可以知道,HashSet在添加元素时,都是采用默认创建的PRESENT对象作为value填充到HashMap中的。因此可以实现利用HashMap来完成HashSet的操作。
小结:
1.对于HashSet中保存的对象,主要要正确重写equals方法和hashCode方法,以保证放入Set对象的唯一性
2.虽说是Set是对于重复的元素不放入,倒不如直接说是底层的Map直接把原值替代了(这个Set的put方法的返回值真有意思)
3.HashSet没有提供get()方法,愿意是同HashMap一样,Set内部是无序的,只能通过迭代的方式获得
LinkedHashSet(可以实现有序插入)
TreeMap默认按键的自然顺序升序进行排序
TreeSet特点与实现机制
TreeSet中存放的元素是有序的(不是插入时的顺序,是有按关键字大小排序的),且元素不能重复
而如何实现有序存储,就需要有一个比较器,其实说起来,TreeSet更受关注的是不重复且有序,这个有序就需要有一个compare的过程,因此会需要参数实现Comparable接口。
另外所有Set集合都不提供get方法,因为Set里面没有索引,若想遍历Set集合元素,有如下两种方式:
1、采用迭代器
2、增强for循环.
TreeMap底层实现数据结构是红黑树
PriorityQueue、LinkedBlockingQueue、ArrayBlockingQueue的实现以及区别;(太深)
HashMap的底层实现,扩容过程,达到阈值一定会扩容吗、put过程、树化过程,如何确定负载因子(有兴趣的可以看一下)、以及为什么线程不安全和1.8做了哪些优化;(太深)
HashMap与HashTable的区别(不知道都喜欢问这个,HashTable已经弃用了),如何获得一个线程安全的Map;
ConcurrentHashMap为什么是线程安全的,以及1.8做了哪些优化;
ConcurrentHashMap原理分析(锁分离技术)
1 、结构
由hash表、segment(桶)、hashEntry(节点)组成
注:每个segment都继承了ReentrantLock
2、hash过程
步骤一:第一次hash,h1=hash1(key);
步骤二:第二次hash找出segment的位置,h2=hash2(h1高几位)
步骤三:第三次hash找出hashEntry的位置,h3=hash3(h2)
- 插入时从hashEntry链表的头插入,删除时会拷贝一份新的数据链,删除线程和遍历线程不会相互影响
3、concurrentLevel:并发级别,决定segment的个数,最大为1<<16
换句话说,segment的个数代表了并发量
JDK1.8之后的改进:
链表改成了红黑树,当链表中的结点达到一个阀值TREEIFY_THRESHOLD时,会将链表转换为红黑树,查询效率提从原来的O(n),提高为O(logn)
将每个segment的分段锁ReentrantLock改为CAS+Synchronized
问题汇:
- HashMap的get和put的工作原理?
1、数组+链表的结构
2、get(key)时,会用key做一次hash运算得到hashcode,根据hashcode找到数组的位置,然后查看对应数组下是否有链表,有则遍历看链表中的结点Node是否有key相等的结点,如果有则返回此结点的value,无则继续