当前位置: 首页 > 面试经验 >

阿里云3.18最新后端面经解析:

优质
小牛编辑
84浏览
2024-03-20

阿里云3.18最新后端面经解析:

讲一下map,讲一下HashMap吧
答:Map是一种专门用来搜索的数据结构,它经常用来存放键值对。Map允许我们在查找的时候进行插入和删除操作,这使得它在处理这类任务时非常高效。Map的使用与其实例的子类有关,因此不同的Map实现可能会有不同的搜索效率。

HashMap是Map接口的一个实现类,它主要适用于插入、删除和定位元素的操作。HashMap基于哈希表实现,它利用哈希函数(如hashCode())将键(key)转化为数组的索引(index),然后根据这个索引来存储和查找键值对。这种机制使得HashMap在插入、删除和定位元素时具有非常高的效率。

然而,HashMap并不保证键的顺序,也就是说,遍历HashMap可能会得到不同的顺序结果,除非在特定的构造器中进行排序。如果需要有序的遍历,那么可能会选择其他类型的Map,比如TreeMap。

当不同的键通过哈希函数运算得到相同的索引时,就会发生哈希碰撞(或哈希冲突)。HashMap通过链表或红黑树(在Java 8及以后的版本中,当链表长度超过一定阈值时,链表会转化为红黑树)来解决这种冲突,这种策略被称为拉链法。

你说到了链表长度为8的时候会转换为红黑树,为什么是8呢?
答:当HashMap中的某个桶(bucket)的链表长度达到8时,会触发树化(treeifyBin)操作,将链表转换为红黑树。这是为了优化性能,因为红黑树的查找、插入和删除操作的时间复杂度都是O(log n),而链表在长度较长时的这些操作的时间复杂度为O(n)。当桶中的元素数量较少时,链表操作已经足够高效,因此没有必要转换为红黑树。

另外,链表长度超过8并不是唯一触发树化的条件。还有一个条件是桶的总数超过64。也就是说,如果HashMap中的桶的总数超过64,并且某个桶的链表长度达到8,那么链表就会转换为红黑树。这是为了避免过多的树化操作,因为红黑树的空间占用相对于链表来说要大一些。

至于为什么选择8和64这两个数字,它们是通过实验和性能测试得出的经验值。这些值在大多数情况下都能提供较好的性能和空间使用效果。当然,具体的实现可能会因Java版本的不同而有所差异,但背后的设计思想和权衡是相似的。

HashMap为什么线程不安全?
答:
扩容:当HashMap中的元素数量超过其容量时,会触发扩容操作。这个操作涉及到生成新的数组、重新计算原有键值对的位置,并写入新的数组。如果在多线程环境下,多个线程同时检测到需要扩容并尝试执行resize操作,这可能导致数据不一致、死循环或死锁。例如,某些线程可能已经完成赋值,而其他线程刚开始赋值,这样就可能用已经被赋值的table作为原始数组,从而导致问题。

put和get操作的非原子性:在HashMap中,put和get操作并不是原子性的。这意味着在多线程环境下,一个线程可能正在执行put操作(包括计算哈希值、确定索引和存储键值对等步骤),而另一个线程可能同时执行get操作,这可能导致get到的值并不是最新的或者预期的值。

删除操作的问题:当在HashMap中删除某个键值对时,实际上是删除了该键值对在内部数组中的对应位置。如果有多个线程同时尝试删除不同的键值对,它们可能会相互干扰,导致数据不一致。

线程池参数有哪些?
答:线程池的参数主要包括以下几个方面:

corePoolSize:线程池中的常驻核心线程数。这些线程在创建线程池后就会立即启动,即使它们当前并没有任务执行。
maximumPoolSize:线程池能够容纳同时执行的最大线程数。当工作队列已满,并且正在执行的线程数达到这个值时,线程池就不会再创建新的线程。这个值必须大于等于1。
keepAliveTime:多余的空闲线程的存活时间。当线程池中的线程数超过corePoolSize,并且这些多余的线程在keepAliveTime这段时间内没有执行任务,那么它们就会被销毁,直到线程池中的线程数减少到corePoolSize为止。
unit:keepAliveTime的单位,比如可以是TimeUnit.SECONDS、TimeUnit.MILLISECONDS等。
workQueue:任务队列。当线程池中的线程都在忙时,新提交的任务会存放在这个队列中等待执行。
threadFactory:线程工厂,用于创建新的线程。一般情况下,我们可以使用默认的线程工厂,但如果需要自定义线程的创建方式,比如设置线程名、设置线程优先级等,就需要使用自定义的线程工厂。
handler:拒绝策略。当队列已满,并且线程池中的线程数已达到maximumPoolSize时,如果还有新的任务提交,就需要根据这个策略来处理这个新任务。常见的拒绝策略有:直接抛出异常、使用调用者的线程来运行任务、丢弃这个任务、丢弃队列中最老的任务然后尝试提交新任务等。

怎么关闭线程池?

shutdownNow()为什么有些任务无法取消?

TreadLocal是干嘛的?原理是什么?

ThreadLocal会导致什么问题?

synchronized 和 ReentrantLock 有什么区别?

ReentrantLock是怎么实现的?AQS?讲一下AQS?他是怎样获取锁的?

Semaphore和CountDownLatch有了解过吗?

讲一下Java有哪些IO模型

你知道select和epoll有什么区别吗?

零拷贝有哪些实现方式?

用过Java哪些框架?springboot是用来解决什么问题的?spring呢?

说一下jvm内存区域划分

说一下本地方法栈和java虚拟机栈的关系

一个啥啥啥String语句***它的各部分在内存的哪?当时没听明白,应该是想问字符串常量池和堆

还有一个啥啥啥是怎么加进jvm内存的,也没听懂。说了下类加载过程。又问就是这个class文件pilipala***

有做过jvm调优吗?

垃圾回收算法有哪些?

了解哪些最新的垃圾回收器?

MySQL有哪些锁?

事务有哪些隔离级别

readview是干嘛的?

除了可重复读就没别的地方使用readview了吗?

ReadView的结构。这三个问题他都想引导我说undolog,没反应过来。

宕机了,redolog是怎么保证持久性的?

binlog和redolog的区别?

如何实现binlog和redolog的同步?

讲一下zookeeper的底层原理

除了ZAB,还知道哪些分布式一致性协议?

拷打项目

你这个项目,还有什么别的实现方式吗?

说一下你对最终一致性和强一致性的理解

既有最终一致性又有强一致性不会冗余吗?

消息队列里面怎么保证一致性?

为什么会想要自己实现一个rpc?

手撕 lc287 寻找重复数

上来就拷打了五十分钟八股,人已经面麻了
 类似资料: