面试-java基础
集合-高频面试题
编辑
HashMap 在JDK1.7 和JDK1.8 中差别
-
数据结构
-
JDK 1.7:HashMap在JDK 1.7中是基于数组和链表的实现。当发生哈希冲突时,会使用链表头插来解决冲突。
-
JDK 1.8:HashMap在JDK 1.8中引入了红黑树(Red-Black Tree)来优化链表。当链表长度超过一定阈值(默认为8,并且数组长度大于64,否则会先扩容)时,链表会转换为红黑树,以提供更快的查找、插入和删除操作。
-
-
插入和扩容时的顺序
-
JDK 1.7:在插入新元素或扩容时,HashMap会重新计算元素的hash值,并根据新的hash值重新定位元素在数组中的位置。这个过程可能导致元素的顺序发生变化,尤其是在并发环境下,可能导致链表成环的问题。
-
JDK 1.8:JDK 1.8优化了插入和扩容时的顺序问题。扩容时,HashMap会尽量保持原有链表的顺序(倒数第五位的值是0,下标不变,倒数第五位的值是1,原来下标的2倍),并且新插入的元素会被放到链表的尾部,从而避免了链表成环的问题。
-
-
hash值的计算
-
JDK 1.7:hash值的计算采用了9次扰动(4次位运算+5次异或运算),并且hash值在插入后不可改变。
-
JDK 1.8:hash值的计算采用了2次扰动(1次位运算+1次异或运算),并且hash值在插入后不可改变(final修饰)。这种变化减少了hash计算的复杂性,提高了性能。
-
-
扩容策略
-
JDK 1.7:HashMap在扩容时会先创建一个新的数组,然后将原数组中的元素重新计算hash值并插入到新数组中。这个过程可能导致大量的数据迁移和重定位。
-
JDK 1.8:HashMap在扩容时采用了更优化的策略。如果原数组容量未达到64,则直接扩容2倍;如果原数组容量超过64,且链表长度大于8,则将链表转换为红黑树;如果红黑树中的元素个数小于6,则红黑树会还原为链表。这种策略在保持性能的同时,减少了数据迁移和重定位的开销。
-
-
并发控制
-
JDK 1.7:HashMap本身不是线程安全的,需要外部同步措施来确保线程安全。
-
JDK 1.8:虽然HashMap在JDK 1.8中仍然不是线程安全的,但由于其内部结构的优化和扩容策略的改变,它在并发场景下的性能得到了提升。
-
HashMap 的长度为什么是2的幂次方
可以用(length - 1)&hash
这种位运算来代替%取余的操作进而提高性能。
为什么树化的临界值为8
当桶中结点个数为8时,出现的几率是亿分之6的,因此常见的情况是桶中个数小于8的情况,此时链表的查询性能和红黑树相差不多
ConcurrentHashMap 在JDK1.7 和JDK1.8 中差别
在 HashMap基础上增加了线程安全的设置
在JDK 1.7中,锁住整个Segment段
ConcurrentHashMap主要由Segment数组、HashEntry数组以及ReentrantLock组成。每个Segment都是一个ReentrantLock,可以锁住一段哈希表结构,从而实现分段锁。整个ConcurrentHashMap基于分段锁实现,提高了并发性能。然而,当HashEntry链表过大时,查询效率可能会降低。
而在JDK 1.8中,synchronized只锁定当前链表或者红黑树的首节点
ConcurrentHashMap进行了重大改进,摒弃了Segment,采用了synchronized+CAS+红黑树实现的数据结构。锁的粒度也从段锁缩小为结点锁,进一步提高了并发性能。此外,JDK 1.8还优化了put()方法的执行流程,只需要一次定位,并采用CAS+synchronized的机制进行加锁,降低了锁资源的争夺。当链表长度超过一定阈值时,链表会转换为红黑树,以提供更快的查找、插入和删除操作,从而解决了JDK 1.7中查询效率较低的问题
并发编程-高频面试
线程与进程的区别?
进程是资源分配的最小单位,它包含执行代码、系统资源和线程。线程是CPU调度的最小单位,共享进程资源,更轻量。进程间不共享内存,线程间共享内存空间。进程间通信需要进程间通信(IPC)机制,而线程间可以直接读写共享内存进行通信。
什么是线程的上下文切换?
线程的上下文切换是指CPU从一个线程切换到另一个线程时需要保存当前线程的状态(如程序计数器、栈指针等),并恢复下一个要执行线程的状态的过程。
Java中的线程有几种创建方式?
Java中创建线程主要有三种方式:
-
继承Thread类并重写run()方法。
-
实现Runnable接口并重写run()方法,然后将Runnable对象作为参数传递给Thread类的构造函数。
-
实现Callable接口并使用FutureTask包装,通过线程池执行。
什么是线程的生命周期?
线程的生命周期通常包括新建(New)、就绪(Runnable)、阻塞(Blocked)、运行(Running)、终止&