4. 上海数慧面试复盘--电话面试
结果:
挂了
时间
2023.2.26
心得
紧张,说话不自信,吞吞吐吐
八股没背,回答的点不是很清晰,深挖一下就不行了
分布式锁相关问题回答得也不是很好
注: ----- 以下答案不再更新(考虑删除),统一在面试宝典中更新
索引的原理是什么?
通过数据结构进行高效查询,mysql默认为B+树,然后讲一下B+树的特点,和其他树的区别
你看了集合的源码,主要有哪些?
ArrayList、HashMap、ConcurrentHashMap这些(源码跟着b站或者咕泡再看看,一定要亲手点一点)
我比较熟悉的是 HashMap 这一块
那你讲讲 HashMap 吧?
HashMap 是一种基于哈希表实现的 key-value键值对形式的数据结构。可以在 O(1) 的时间复杂度内对元素进行操作。
首先讲一下 hashMap 的底层数据结构:
底层采用数组+链表的形式去进行存储,在1.8的时候引入了红黑树,主要是对链表去做一个转化,进行效率的提升(引诱面试官提问链表和红黑树的转换)
hashmap的初始容量是16,扩容方式是2的幂
隐藏点:链表和红黑树的转换
如果链表长度超过8,并且数组长度大于64,就转换为红黑树;
如果链表长度小于等于 6 ,红黑树重新转化为链表
然后讲一下 put 方法的过程:
hashmap对 key 求哈希值然后计算下标,如果没有 哈希碰撞 就直接插入, 如果碰撞了就以链表的形式链接到后面。(引诱面试官提问哈希值计算过程)如果节点已经存在就替换旧值。
如果元素总个数大于 阈值(threshold) (容量 * 加载因子0.75) 就 resize 扩容,扩容还发生在当链表长度大于 8 但是此时数组容量小于 64 ,主要是为了扩容后让节点分步更均匀一些。
然后讲一下 HashMap 的哈希函数怎么实现:
(h = key.hashCode())^ (h >>> 16),首先调用 hashCode() 方法对 key 求 hash值,然后将hash值得低 16 位bit和高 16 位 bit 做异或运算获得 新的 hash 值,然后 (n - 1) & hash 获得下标 (n 指数组的长度)
为什么要和高16位进行 ^ 运算?
由于和 (length -1) 运算,length 绝大多数情况小于 2 的 16 次方。 所以始终是 hashcode 的低 16 位(甚至更低) 参与运算。 但是这样高 16 位是用不到的,为了让得到的下标更加散列,需要让高16位也参与运算,所以就需要低16位和高16位进行 ^ 运算。
为什么 & 位必须是(length - 1)?
长度是2的幂次,length -1 的所有二进制都是1,相当于 取余数,但是比 % 运算更快, table[i = (n -1)& hash];
为什么用 ^ 而不是用 & 或 |
因为 & 和 | 都会使结果偏向 0 或者 1,并不是均匀的概念,所以用 ^。
然后讲一下 hashmap 线程并发安全问题
多个线程同时 put , 当 put 的 key 一样造成一个线程 put 的数据被覆盖
多个线程同时检测到元素个数超过数组大小 * loadFactor, 同时对Node 数组 进行扩容,都重新计算元素位置和复制数据,最终只有一个线程扩容后的数据会复制成功,其他线程丢失,并且 put 的数据也丢失。
链表和红黑树转换的时候会抛出类型转化异常:两个线程同时将红黑树转换成链表,一个线程转换成功,红黑树变成链表了,另一个线程开始转换就会发现红黑树变成了链表,就会抛出类型转化异常。
hashMap 是怎么扩容的?
HashMap 的扩容操作分为两个步骤:
- 创建一个新的数组,长度是当前数组长度的两倍。
- 将原数组中的元素重新映射到新数组中的位置。这个过程需要重新计算每个元素的哈希值,然后重新映射到新数组的位置中。如果新数组中的某个位置已经有了元素,则需要进行链表或红黑树的操作,以保证元素可以正确地插入到数组中。
concurrenthashmap 了解吗?
保证线程安全的方式有哪些?
保证线程安全主要是保证它的原子性、可见性和有序性
基于synchronized的同步代码块和同步方法,然后使用锁、使用并发集合、使用原子类
使用CAS:保证共享变量的线程安全
使用ThreadLocal: 线程本地变量
volatile 能保证线程安全吗?
不能,volatile 不具备原子性,当多个线程进行 i++ 操作,最后结果是不准确的
ReenTrantLock和Synchronized区别
首先都是可重入锁,然后他们的区别主要有几个方面,第一个是锁的实现不同,
synchronized是JVM实现的关键字
ReentrantLock是JDK实现的类
第二个是性能,
synchronized与ReentrantLock大致相同,但是新版本Java对synchronized进行了很多优化,如自旋锁
第三个是等待可中断
可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,处理其他事情
ReentrantLock可中断
synchronized不可中断
第四个是公平锁
synchronized的锁是非公平的
ReentranlLock默认非公平,也可以调为公平
第五个是可以实现选择性通知
一个ReentrantLock可以同时绑定多个Condition对象,可以指定线程信息去实现选择性通知
讲一下Spring Bean的生命周期
Spring 中的 bean 的生命周期是指bean从创建到销毁的一个过程,主要包含四个阶段:
- 实例化 Bean
- Bean 属性赋值
- 初始化 Bean
- 销毁 Bean
(面试官如果问初始化这块,就简单说一下 aware,前后置初始化,自定义初始化这些)
Spring学习了哪些内容?
复盘过,重新整理答案出来
动态代理在哪里有用到?
aop,rpc,事务管理,数据库连接池
项目上用到了哪些设计模式?
策略模式,讲一下自己写的比较方法的策略模式+简单工厂模式
文章访问量、博客PV、UV怎么做的?
通过redis去统计每天的访问量,通过定时任务将访问量同步到数据库。同时将pv、uv通过日志统计的形式同步到数据库。
面试官评价
简历写得还行,问起来就一般