惯例:自我介绍和近期深刻的项目介绍。
1. HashMap 的底层数据结构是怎样的 ?
底层是用数组实现,hash冲突使用拉链法解决,节点超过8转换成红黑树
2.HashMap哈希算法是怎么实现的,为什么很实现?
key的hashcode高16位不变,然后高16位与低16位与或运算,在只有低位参与索引位置的情况下,为了防止高位不同,低位相同的冲突
3. 有哪几种哈希算法,都有什么特点?
拉链法(冲突对象形成一条链表);在hash法(有多个不同的hash函数,直到找到空位);寻址法(一个hash函数,会hash结果上以某种规律变化,知道找到空位)
4. HashMap1.7并发死循环能通俗的讲下吗?具体在哪里为什么会成环
由于7在扩容是,链表是头插的方式进行,假如有两个node始终冲突,在执行node.next方法时,恰好有另外一个线程也进行了扩容,扩容一个节点,切回一线程,这时一线程next是新map的节点,当下个循环时会在插入这个节点,结果产生死循环
5.G1和CMS有什么区别
G1是整堆收集器,cms只是老年代收集器
G1整体是标记整理,局部标记复制,cms是标记清除
G1不会产生垃圾碎片,cms会有碎片
G1是目标是降低停顿时间,cms目标是提高吞吐量
6.G1的停顿时间判断怎么确定的?
和用户设置的最大停顿时间作为标准,然后决定回收哪些region,时间长回收region多
7.G1是以什么方式什么时候判断regin上的垃圾回收成本
是以可达性分析方式标记垃圾,在重新标记阶段会计算每个region的回收成本,
8.线程池的核心数和最大数有什么区别
核心可以空闲不销毁,最大需要销毁
9.核心数怎么确定,最大数怎么确定
具体和业务和机器性能相关,我总结可以这样计算 预期QPS/(1000/接口性能) 例如 10000/(1000/200) 10000是预期QPS,1000是一秒,200是接口性能。以这个结论作为初始设置,然后根据压测进行调整
10.队列使用有界还是无界,阻塞还是非阻塞,为什么
基本都是有界阻塞队列
阻塞使用锁控制并发,并发度高比较适合,阻塞线程,释放CPU,
非阻塞并发高的浪费CPU,并发低阻塞队列的syn自旋也能提高,只是有时间限制,所有使用场景比较苛刻,并发低比较适合
有界队列可以控制等待线程的上限,底层是Array,初始占用空间比较多,数组初始化就确定空间大小
无界队列使用的前置条件是请求有上限限制,没有限制会OOM,按需产生节点,不会浪费空间,但是会 额外封装node节点形成链表
11.淘汰策略有几种,分别用在什么场景
简单说几个;丢弃最新的和丢弃最老的,适合收集info日志这类无关紧要的场景
抛异常,适合对任务进行二次处理,比如路由到异步MQ中
调用节点执行,适合重要并快速响应的场景(但是有坑)
12.线上使用线程池,线上有遇到问题吗
核心设置不够队列太大导致超时
队列选择不对导致OOM(无界队列),CP飙高(非阻塞队列),
淘汰策略是调用节点执行,导致服务不可用,占用过多线程,突破线程池隔离