题目:
1、网卡零拷贝。
2、说一下 TCP 的拥塞控制,知道慢启动吗?
3、项目中的你是如何设计包头的,内容有啥。 然后如果让你设计一个类似tcp/ip的包头,要有哪些字段?
4、TCP 的拆包粘包。 如果不提前知道包长,数据内又有/0这种分割包的特殊字符,应该怎么办?(转译,当时没答出来)
5、解释一下 hashmap 为什么用红黑树代替链表? 为什么不用avl树?
6、concurrentskiplist是什么结构,如何查询的?如何回退的?
7、项目为什么用 concurrenthashmap?如何保证线程安全的? hashmap多线程为什么不安全?(答了会链表回环,然后又问具体是怎么成环的,没打出出来。。。。)
8、hashmap扩容时如何进行挪移的?
9、解释一下list
10、concurrenthashmap 的size()是怎么做的?
11、hashmap、hashtable、concurrenthashmap 比较
12、synchonize关键字。是不是公平锁?为什么是不公平锁?
13、LRU和LFU。
14、mysql事务隔离级别,有什么区别?有什么用?
15、表锁和行锁都是什么时候加?
16、什么是聚簇索引?
17、mybats介绍一下 $和#的区。
18、介绍一下redis ,说一下缓存击穿,穿透,雪崩。然后怎么避免。
19、说一下布隆过滤器,然后如何减少误判。
20、然后无序数组不排序如何查找中位数(类似快排)
问题 1:网卡零拷贝
网卡零拷贝(Zero Copy Networking)是一种技术,旨在减少数据在计算机系统内部传输时的复制次数,从而提高网络性能和吞吐量。
在传统的网络数据传输中,数据需要从应用程序缓冲区复制到内核缓冲区,然后再复制到网卡的缓冲区,最后才能通过网络发送。这些复制操作会占用大量的 CPU 时间和内存带宽,降低系统性能。
而通过使用网卡零拷贝技术,数据可以直接从应用程序缓冲区传输到网卡缓冲区,而无需经过内核缓冲区。这样可以减少数据复制的次数,减少 CPU 和内存的负担,从而提高系统性能和吞吐量。
网卡零拷贝技术可以通过多种方式实现,例如使用 DMA(直接内存访问)引擎、RDMA(远程直接内存访问)等。在具体实现中,需要考虑网络协议的支持、硬件设备的兼容性等因素。
问题 2:说一下 TCP 的拥塞控制,知道慢启动吗?
TCP 通过拥塞控制来避免网络拥塞,保证网络的稳定性和可靠性
拥塞控制过程中涉及到四个算法:慢开始算法、拥塞避免算法、快重传算法、快恢复算法
在发送方维护三个变量:
看下图来说明拥塞控制过程:
当 TCP 建立链接后,执行慢开始算法,先将 swnd = cwnd = 1,然后发送报文,每次收到一个确认报文,那么拥塞窗口 cwnd 会指数级增长,比如:
在慢开始算法阶段,拥塞窗口的大小是指数级增长的,直到达到一个阈值 (ssthresh) 为止,就执行拥塞避免算法
拥塞避免算法每次发送完报文,收到确认报文后,拥塞窗口自动 +1,这个是线性增长
当发生超时重传,也就意味着网络出现了拥塞,这个时候会做两件事:
当拥塞窗口值达到了 ssthresh 阈值后,又开始拥塞避免算法
在执行拥塞避免算法时,如果收到了 3 个重复确认报文的话,则执行快重传算法,就是将相应的报文立刻重传,而不是等到超时重传
这样,对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞,进而不会将拥塞窗口降低为 1,使用快重传可以使整个网络的吞吐量提高约 20%
执行完快重传算法后,立即执行快恢复算法,即:将发送方慢开始阈值 ssthresh 和拥塞窗口 cwnd 调整为当前窗口的一半,然后开始执行拥塞避免算法
问题三:项目中的你是如何设计包头的,内容有啥。 然后如果让你设计一个类似 tcp/ip 的包头,要有哪些字段?
在网络通信中,包头通常包含了与数据传输相关的各种信息,例如数据长度、协议版本、数据类型、数据校验和、传输编码方式等。在项目中,设计包头需要考虑以下几个方面:
在设计包头时,还需要考虑到包头大小的问题,如果包头太大,将会占用过多的网络带宽,降低数据传输的速度。因此,需要根据具体情况设计最小的包头大小,以便在保证数据传输可靠性的同时,尽可能减少网络带宽的占用
让你设计一个类似 tcp/ip 的包头,这个问题其实就是问你 tcp、ip 包头中的常用字段及其含义了
以下是 ip 首部字段:
以下是 tcp 首部字段:
问题 4:TCP 的拆包粘包。 如果不提前知道包长,数据内又有/0这种分割包的特殊字符,应该怎么办?
TCP 是面向字节流的,而一个消息包可能包含多个字节,所以当使用 TCP 传输消息包的时候,就会出现:
不管是粘包问题,还是半包问题,都会使得接受者解析消息包失败,应用进程无法从一个粘包、半包中解析出完整的消息
出现粘包半包问题的根本原因就是:TCP 时面向字节流的,消息没有边界
要解决粘包含半包问题的根本手段是:找出消息的边界
有以下三种方式可以找出消息的边界:
分隔符也有个缺点:数据内容本身出现分隔符时,需要对这个分隔符进行转义
所以每次发送消息时,需要扫描一遍消息,看看有没有出现分隔符,有的话则将其转义
这种方法的优点:精确定位消息内容,内容不需要额外的转义
缺点:消息内容长度有限制,需要提前知道可能的最长的消息的字节数
这个问题我在我的 B 站中有视频讲解:资深程序员老汤
问题 5:解释一下 hashmap 为什么用红黑树代替链表? 为什么不用avl树?
这道题目的是问你红黑树和 AVL 树的区别,各自的使用场景是什么
红黑树和 AVL 树都是一种常用的自平衡二叉搜索树,它们的主要目的是保证树的高度平衡,从而保证搜索、插入和删除等操作的时间复杂度都是 O(log n) 级别的。
红黑树和 AVL 树的主要区别包括以下几点:
1. 平衡性的要求不同:
AVL 树要求任何节点的左右子树的高度差(平衡因子)不超过 1,因此它的高度更加严格地控制在 O(log n) 级别,搜索效率更高。而红黑树则只要求黑色节点的数量相等,因此它的高度可以略微超过 O(log n) 级别,但是因为旋转操作的次数更少,所以它的插入和删除操作通常比 AVL 树更快。
2. 节点结构不同:
AVL 树的节点需要记录平衡因子,因此它的节点结构比红黑树更加庞大。而红黑树只需要记录颜色信息,因此节点结构相对更为简单,可以节省内存空间。
3. 插入和删除操作的实现不同:
AVL 树在插入和删除节点时需要通过旋转操作来保持平衡,因此它的操作相对复杂。而红黑树通过颜色变换和旋转操作来保持平衡,操作相对简单。
可以看出,红黑树和 AVL 树都是自平衡二叉搜索树,它们的实现方式不同,各有优缺点。红黑树适用于插入、删除操作较多的场景,而 AVL 树适用于搜索操作较多的场景。而 HashMap 会用于插入和删除较多场景,并且从空间的角度来看的话,使用红黑树比较合适
问题 6:concurrentskiplist 是什么结构?如何查询的?如何回退的?
在 Java 中,好像没有 concurrentskiplist,只有 concurrentskiplistMap 和 concurrentskiplistSet
我们可以把 concurrentskiplistMap 和 concurrentskiplistSet 都看成 concurrentskiplist 结构
concurrentskiplist 底层是跳表,而且是一个并发安全的跳表
跳表其实就是一个有序的链表,为了高效的保证链表有序,在链表上加了几层索引
查询的时候, 先比对跳表中的索引,根据索引来定位需要查找的数据在链表中的位置
concurrentskiplistMap 和 concurrentskiplistSet 都没有回退的 API 哈,不知道面试官问这个是什么意思
问题 7:项目为什么用concurrenthashmap?如何保证线程安全的? hashmap多线程为什么不安全?
答:用 concurrenthashmap 的目的是为了保证线程安全
在 JDK 1.7 中,ConcurrentHashMap 使用了分段锁,即将哈希表分成多个段,每个段拥有一个独立的锁。这样可以在多个线程同时访问哈希表时,只需要锁住需要操作的那个段即可,而不是锁整个哈希表
这种分段锁虽然可以减少锁竞争,但是在高并发场景下,仍然会出现锁竞争,从而导致性能下降,所以在 JDK 1.8 中,对 ConcurrentHashMap 的实现进行了优化,采用 CAS + Synchronized 的机制来保证线程安全
在 JDK 1.8 中,ConcurrentHashMap 会在添加或者删除元素时,首先使用 CAS 操作来尝试修改元素,如果 CAS 失败,则使用 Synchronized 锁住当前的槽,再次尝试调加或者修改,这样锁的粒度减少,锁的竞争也变少,提高了并发性
HashMap 多线程为什么不安全呢?以下四个原因:
问题 8:hashmap 扩容时如何进行挪移的?
答:假设扩容前的数组是 oldTab,它容量是 oldCap,扩容后的数组是 newTab,它的容量是 newCap = 2 * oldCap
遍历 oldTab 的所有的桶,假设这个桶在数组中的索引是 j
然后,判断每个桶,分三种情况:
问题 9:解释下 list
List 是一种线性集合,实现了 Collection 接口,它具有如下特点:
问题 10:concurrenthashmap 的 size()是怎么做的?
以下说的是 JDK 8 及其后面版本的 size() 的实现
在 ConcurrentHashMap 中维护了两个成员变量:
其中,CounterCell 的源码是这样的:
@jdk.internal.vm.annotation.Contended static final class CounterCell { volatile long value; CounterCell(long x) { value = x; } }
在往 ConcurrentHashMap put 键值对成功后:
那么,在 size() 方法中,计算键值对数量等于:baseCount 的值和 counterCells 中所有元素的 value 值累加
问题 11:hashmap、hashtable、concurrenthashmap 比较
三者的比较如下:
问题 12:synchronized 关键字。是不是公平锁?为什么是不公平锁?
synchronized 关键字主要用来加锁,从而保证程序的同步,线程安全,synchronized 添加锁有以下几个特点:
synchronized 的使用方法比较简单,主要可以用来修饰方法和代码块
synchronized 加的锁是不公平的,因为 synchronized 获取锁的行为是不公平的,并非是按照申请对象锁的先后时间分配锁的,每次对象锁被释放时,每个线程都有机会获得对象锁,这样有利于提高执行性能,但是也会造成线程饥饿现象
问题 13:LRU 和 LFU。
LRU 是 Least Recently Used 的缩写,意思是最近最少使用,也可以理解成最久未使用
LFU 是 Least Frequently Used 的缩写,意思是最不常用
LRU 和 LFU 一般作为缓存淘汰算法,在缓存满了的时候:
对于 LRU 算法,我们可以使用 HashMap + 双向链表来实现,HashMap 存储数据,双向链表维护键值对的顺序,对于被访问的数据放到双向链表的表头,那么链表表尾的数据就是最久不常用的数据了,可以优先淘汰掉
对于 LFU 算法,我们可以使用 3 个 HashMap 来实现,他们的作用分别是:
我们还需要有一个变量 minUsedCount 来记录目前最小使用次数,根据 minUsedCount 就可以去第三个 HashMap 中找到使用次数为 minUsedCount 的所有 key,然后找到最久未使用的 key ,淘汰即可
问题 14:mysql事务隔离级别,有什么区别?有什么用?
MySQL 提供了不同的事务隔离级别,用于控制并发事务之间的互相影响程度。以下是MySQL中常见的四个事务隔离级别,按照严格程度递增排列:
选择适当的事务隔离级别取决于应用程序的需求和并发访问的特点。较低级别的隔离级别可以提供更高的并发性能,但可能导致数据不一致的问题。较高级别的隔离级别可以提供更严格的数据一致性,但可能牺牲一定的并发性能。
在实际应用中,可以根据具体情况选择合适的隔离级别。如果应用程序对数据一致性要求较高,可以考虑使用可重复读或序列化隔离级别。如果对并发性能要求较高,并且可以容忍一定程度的数据不一致,可以选择读已提交或读未提交隔离级别。
问题 15:表锁和行锁都是什么时候加?
表锁:表锁是在执行一些特定操作时(如 ALTER TABLE、TRUNCATE TABLE、RENAME TABLE等)或使用LOCK TABLES 语句时加上的。表锁会锁定整张表,阻塞其他事务对该表的读写操作,直到当前事务释放锁。表锁对并发性能的影响较大,因为其他事务无法同时访问相同的表。
行锁:行锁是在事务对表中的行进行修改或查询时加上的。行锁的引入是为了提高并发性能,只锁定需要修改或查询的行,而不是整张表。行锁可以防止其他事务修改或删除被锁定的行,但允许其他事务同时对其他行进行操作。
问题 16:什么是聚簇索引?
在 MySQL 中,聚簇索引决定了表中数据的物理存储顺序。聚簇索引的主要特点是数据行的物理顺序与索引的顺序一致。
当创建聚簇索引时,MySQL 会根据指定的列或列组织表的数据存储方式。这意味着具有相邻索引值的行将物理上存储在一起,形成一个数据页。这种存储方式使得数据库系统可以更高效地获取具有连续索引值的行,因为它们在物理上相邻,减少了磁盘I/O操作。
由于聚簇索引决定了数据的物理存储顺序,因此每个表只能有一个聚簇索引
问题 17:mybatis介绍一下 $和#的区别。
$ 和 # 是用于参数替换的两种不同的占位符符号
使用 $ 作为占位符时,MyBatis 会直接将参数的值替换到 SQL 语句中,不进行预编译处理。这意味着参数值直接嵌入到 SQL 语句中,可能存在 SQL 注入的风险。$占位符可以用于替换表名、列名、SQL表达式等
使用 # 作为占位符时,MyBatis 会将参数值以预编译参数的形式传递给数据库,从而提供了更好的安全性和可移植性。# 占位符可以用于替换查询条件、插入、更新等操作的参数
问题 18:介绍一下redis ,说一下缓存击穿,穿透,雪崩。然后怎么避免。
参考我的上一篇面经总结:
问题 19:说一下布隆过滤器,然后如何减少误判。
布隆过滤器本质上就是哈希函数 + 位图
减少误判的两种方法:① 增加哈希函数的数量;② 增加位图的长度
这个问题我在我的 B 站中有视频讲解:资深程序员老汤,找到【海量数据处理】的视频即可
20、然后无序数组不排序如何查找中位数
使用堆:大顶堆 + 小顶堆,大顶堆用于存储较小的一半元素,小顶堆用于存储较大的一半元素