#美团#Java面试题:集合高频要点问题你能答上来吗?( 三 )


采用 table 数组元素作为锁 , 从而实现了对每一行数据进行加锁 , 进一步减少并发冲突的概率 。
把 Table 数组+单向链表的数据结构变成为 Table 数组 + 单向链表 + 红黑树的结构 。
当链表长度超过 8 以后 , 单向链表变成了红黑数;在哈希表扩容时 , 如果发现链表长度小于 6 , 则会由红黑树重新退化为链表 。
对于其他详细我不吹 , 看懂的么几个 , 他比 HashMap 还要难 。
对于线程安全环境下介意使用 ConcurrentHashMap 而不去使用 Hashtable 。
3. 为什么不去使用 Hashtable 而去使用 ConcurrentHashMap?
HashTable 容器使用 synchronized 来保证线程安全 , 但在线程竞争激烈的情况下 HashTable 的效率非常低下 。 因为当一个线程访问 HashTable 的同步方法时 , 其他线程访问 HashTable 的同步方法时 , 可能会进入阻塞或轮询状态 。 如线程 1 使用 put 进行添加元素 , 线程 2 不但不能使用 put 方法添加元素 , 并且也不能使用 get 方法来获取元素 , 所以竞争越激烈效率越低 。
4. ConcurrentSkipListMap 与 TreeMap 的选择?
ConcurrentSkipListMap 提供了一种线程安全的并发访问的排序映射表 。 内部是 SkipList(跳表)结构实现 , 利用底层的插入、删除的 CAS 原子性操作 , 通过死循环不断获取最新的结点指针来保证不会出现静态条件 。 在理论上能够在 O(log(n)) 时间内完成查找、插入、删除操作 。 调用 ConcurrentSkipListMap 的 size 时 , 由于多个线程可以同时对映射表进行操作 , 所以映射表需要遍历整个链表才能返回元素个数 , 这个操作是个 O(log(n)) 的操作 。
在 JDK1.8 中 , ConcurrentHashMap 的性能和存储空间要优于 ConcurrentSkipListMap , 但是 ConcurrentSkipListMap 有一个功能:它会按照键的自然顺序进行排序 。
故需要对键值排序 , 则我们可以使用 TreeMap , 在并发场景下可以使用 ConcurrentSkipListMap 。
所以我们并不会去纠结 ConcurrentSkipListMap 和 ConcurrentHashMap 两者的选择 。
5. LinkedHashMap 的使用?
主要是为了解决读取的有序性 。 基于 HashMap 实现的 。
Queue
1. 队列是什么?
我们都知道队列 (Queue) 是一种先进先出 (FIFO) 的数据结构 , Java 中定义了 java.util.Queue 接口用来表示队列 。 Java 中的 Queue 与 List、Set 属于同一个级别接口 , 它们都是实现了 Collection 接口 。
注意:HashMap 没有实现 Collection 接口 。
2. Deque 是什么?
它是一个双端队列 。 我们用到的 linkedlist 就是实现了 deque 的接口 。 支持在两端插入和移除元素 。
3. 常见的几种队列实现?
LinkedList 是链表结构 , 队列呢也是一个列表结构 , 继承关系上 LinkedList 实现了 Queue , 所以对于 Queue 来说 , 添加是 offer(obj) , 删除是 poll() , 获取队头(不删除)是 peek()。
public static void main(String[
args) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
// 1 23
PriorityQueue 维护了一个有序列表 , 插入或者移除对象会进行 Heapfy 操作 , 默认情况下可以称之为小顶堆 。 当然 , 我们也可以给它指定一个实现了 java.util.Comparator 接口的排序类来指定元素排列的顺序 。 PriorityQueue 是一个无界队列 , 当你设置初始化大小还是不设置都不影响他继续添加元素 。
ConcurrentLinkedQueue 是基于链接节点的并且线程安全的队列 。 因为它在队列的尾部添加元素并从头部删除它们 , 所以只要不需要知道队列的大小 ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好 。 收集关于队列大小的信息会很慢 , 需要遍历队列 。


推荐阅读