自媒体
·2023-08-28#面试# 美团java后端面经来喽,以下是八股部分
详情汇总在我的博客https://tangjiayang.github.io/2023/08/18/2023秋招总结/,欢迎大家交流学习!
你在里面用了Redis的那些数据结构?
首先我用到了分布式锁,所以用到了String,还有的话就是redis用作缓存的时候,大多数用的都是String
分布式锁用的是什么命令呢?
setnx
追问:为什么setnx能起到分布式锁的作用呢?
首先是一个单线程的缓存,线程先query一下看看锁里的内容是不是null,是null就可以占据,。。不太会说,补一下(⚠️)
分布式锁的目的是保证在分布式环境下对资源的互斥访问,即同一时间只能有一个进程/线程能够获取到该资源的锁。SETNX的特性正好满足了分布式锁的要求,其原理如下:
1.当进程 A 需要获取锁时,它尝试使用SETNX操作写入一个指定的锁键(例如lock:resource)。如果该键不存在,则设置成功,进程 A 获得了锁,并可以执行相应的操作。
2.当其他进程 B、C 等尝试获取同一个锁时,如果键lock:resource已经存在,则SETNX操作返回0,表示设置失败,进程 B、C 认为锁已经被其他进程占用,不能获取到锁。
3.进程 A 在完成操作后,释放锁时,通过DEL指令删除锁键lock:resource,从而释放该锁。
追问:为什么setnx之前还要query?setnx不行吗?
我说的是setnx里面会自动先query一下。
追问:分布式锁是怎么保证原子性的呢?
(⚠️)定时、所有者id、释放锁时使用lua脚本先判断是不是自己的,再进行释放
由于Redis的单线程执行机制,setnx指令不会受到并发的影响,每个指令都会依次执行。这样,即使多个客户端同时执行setnx指令,也能够确保只有一个客户端成功设置了分布式锁(返回1),其他客户端会失败(返回0)。
你有研究过String底层是怎么实现的呢?
不太了解(❌,redis底层得系统地学一下,老是不会太伤了)
留个坑,系统学完redis底层后来填
如果用redis实现一个计数器,怎么做呢?
就是有一个自增的命令
追问:用哪个数据结构呢?
String就可以
追问:命令是什么?
忘记了
incr
追问:你就知道有这个命令是吗,那这个命令能保证原子性吗?
我记得有两个自增的命令,一个可以一个不可以。。
其实:incr和incrby指令都是原子操作
mysql这一块,我有一条sql语句执行很慢,我怎么排查原因呢?
首先就用explain命令看一下索引的执行情况吧,主要看一下type列,如果是all的话,说明使用了全表扫描,我们肯定是要对其建立索引的。
追问:使用explain命令后,重点关注哪些信息?
主要观察索引使用情况,如果使用了索引,再看看使用的索引是否符合我们的预期,如果不是,则进一步分析原因。
(❌)
还是这道题,上次面试刚问了,还没记熟
什么叫回表?
正常情况下(即根据普通索引进行查询时,先查询该记录对应的主键,再去主键所在的B 树中寻找其数据信息)
索引覆盖是什么?
查询的列都在使用的索引或主键中,所以不需要再回主键的B 树中获取记录。
一条SQL的执行过程是什么?
MySQL5.8之前有缓冲区,缓冲区会根据sql语句进行缓存、5.8之后移除了;之后会到解析器中进行词法、语法分析,这一阶段还会把 * 换成表中对应实际的列;之后会进入优化器,这里会产生sql语句的执行方案,最后进入存储引擎进行查询。
(⚠️补一下,见https://tangjiayang.github.io/2023/07/27/MySQL原理学习/)
查询缓存的功能是什么?有什么优缺点?
太简单了
维护缓存需要开销,而且缓存命中率很低(很少会在短时间内出现重复的sql,特殊场景除外)
mvcc 的原理是什么?
mvcc其实是可重复读的实现方式,它是对数据库进行快照的一个操作。具体的实现方式为……(就那四个字段,然后说清楚逻辑即可,详细请看https://tangjiayang.github.io/2023/07/27/MySQL原理学习/
https 的原理是什么?
就知道这是http的一种安全的形式(❌,不会)
追问:安全是怎么实现的呢?
应该是对传输进行了加密
追问:怎么加密的呢?
不是很清楚
HTTPS是一种通过加密传输数据的网络协议,它的原理如下:
1.加密通信:HTTPS 使用了加密算法来保护数据的机密性。在客户端与服务器之间建立连接时,首先会进行一次称为SSL/TLS握手的过程,通过该握手过程来协商加密算法和密钥等信息。然后,通过使用协商的密钥对传输的数据进行加密,确保数据在传输过程中不容易被窃听或篡改。
2.数字证书验证:HTTPS 使用数字证书来验证服务器的身份。数字证书由第三方机构(证书颁发机构,Certificate Authority,CA)签发,包含了服务器的公钥和相关信息。在握手过程中,客户端会检查服务器返回的证书,并验证其有效性和合法性。如果验证通过,客户端会使用证书中的公钥加密传输的数据。
3.对称加密与非对称加密结合:HTTPS 使用对称加密和非对称加密结合的方式来进行加密传输。非对称加密算法用于在握手过程中协商对称加密算法和密钥,这样可以确保密钥在传输过程中不被泄露。对称加密算法用于加密实际传输的数据,对称加密算法的加解密速度更快,保证了性能。
4.安全标识:HTTPS 使用 URL 地址中的 "https://" 来表示当前使用的是安全的加密连接。
总结来说,HTTPS 通过加密通信、数字证书验证、对称加密与非对称加密结合等措施,实现了对传输数据的机密性和完整性的保护。这使得客户端与服务器之间的通信更加安全,可以有效地防止数据被窃听和篡改。
你知道使用http协议通信的客户端和服务器之间是怎么建立连接的、报文是怎么发送的?
http是基于TCP协议进行连接,消息传输的……三次握手四次挥手
(❌,偏题了啊。。。)……三次握手很熟练,but四次挥手没看,一下就露出了马脚,被追着问四次挥手
追问:三次挥手不行吗?
当客户端与服务器之间使用HTTP协议进行通信时,建立连接和报文的发送可以分为以下步骤:
1. 建立连接:
- 客户端发送一个连接请求给服务器,这通常是通过向服务器的IP地址和端口发送连接请求的方式实现的。
- 服务器接收到这个连接请求后,会进行一系列的握手过程来建立连接。这个过程通常是使用TCP协议来完成的。
- 一旦握手成功,客户端和服务器之间就建立了一个持久的连接,可以进行通信。
2. 报文的发送:
- 客户端构建HTTP请求报文,包括请求行、请求头和请求体。
- 客户端将构建好的请求报文通过已建立的连接发送给服务器。
- 服务器接收到请求报文后,会解析其中的内容,包括请求方法、URL、请求头和请求体等。
- 服务器根据请求的内容进行相应的处理,可能是读取数据库、执行业务逻辑等。
- 服务器构建HTTP响应报文,包括响应行、响应头和响应体。
- 服务器将构建好的响应报文通过已建立的连接发送给客户端。
- 客户端接收到响应报文后,会解析其中的内容,包括响应状态码、响应头和响应体等。
- 客户端根据响应的内容进行相应的处理,可能是展示页面、执行下一步操作等。
需要注意的是,HTTP是无状态的协议,每个请求和响应都是独立的,服务器不会记住之前的请求,因此需要使用一些机制(如Cookie、Session等)来维护状态信息。
以上就是使用HTTP协议通信时客户端和服务器之间建立连接和报文的发送过程。具体的实现和细节可能会有所不同,但总体流程相似。
四次挥手把同意对方请求跟自身请求分离开。是因为在客户端请求断开时(客户端发送端->服务器接收端),服务器可能还有数据未发完,所以需要分开操作:
✦先同意对方关闭连接,对方无法传输数据;(第二次挥手)
✦自己若还有数据未发送完,接着发送直至全部发送完毕;
✦请求自身关闭连接;(第三次挥手)
也就是说,三次握手、四次挥手差别就在第二次,有没有把同意对方请求跟自身请求拆分开。
为什么客户端要等2个时长后关闭呢?就是2ML问题?
不清楚(❌)
避免网络不稳定带来的问题, 假如在最后发送ACK请求后直接关闭, 此时由于网络原因Server端没收到, Server就会重试FIN请求 但是此时连接已经关闭了,Server端将无法正常发送报文 或者 发送到错误的地方;
了解http的滑动窗口是什么吗?
(❌很模糊,答了个大意---一次传输多个数据块---记错了)
滑动窗口本质上是描述接受方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据。如果发送方收到接受方的窗口大小为0的TCP数据报,那么发送方将停止发送数据,等到接受方发送窗口大小不为0的数据报的到来。
操作系统线程与进程的区别是什么?
老生常谈,每次都问
java你比较了解是吧,synchronize和Reentlock的底层实现上有啥区别?
synchronize用了对象的内部锁,作为对象信息头部中的一个字段,没加锁为空,加锁被设为线程id
Reentlock维护了一个变量,加锁 1 ,解锁-1,为0说明没加锁。⚠️
Synchronized 和 ReentrantLock 是 Java 中实现线程同步的两种机制,它们在底层实现上有以下区别:
1. 可重入性(Reentrancy):
- Synchronized 是 Java 内置的关键字,具有可重入性(也称为递归性)。这意味着如果一个线程已经获得了某个对象的锁,在释放锁之前,可以多次进入被锁保护的代码块。
- ReentrantLock 是 `Lock` 接口的实现类,也具有可重入性。要使用 ReentrantLock 的可重入特性,需要显式地调用 `lock()` 和 `unlock()` 方法。
2. 获取锁的方式:
- Synchronized 是隐式锁,当线程进入同步代码块时,会自动获取锁,并在代码块结束后自动释放锁。无法手动控制锁的获取和释放。
- ReentrantLock 是显式锁,需要手动调用 `lock()` 方法来获取锁,在合适的地方调用 `unlock()` 方法来释放锁。
3. 可中断性:
- Synchronized 在获取锁的过程中,如果线程被阻塞,无法被中断,只能等待获取锁的机会。
- ReentrantLock 提供了可中断的获取锁的方式。通过调用 `lockInterruptibly()` 方法,如果线程被阻塞,可以通过调用 `interrupt()` 方法中断线程。
4. 公平性:
- Synchronized 是非公平锁,线程在竞争锁时,无法保证获取锁的顺序。
- ReentrantLock 默认是非公平锁,但可以通过构造函数参数设置为公平锁,在锁的竞争中,会按照请求锁的顺序分配锁。
5. 性能:
- 在低级别的锁竞争情况下,Synchronized 的性能优于 ReentrantLock。这是因为 Synchronized 是 JVM 内置的锁机制,可以进行一些优化操作。
- 在高度竞争的情况下,ReentrantLock 的性能可能优于 Synchronized,因为 ReentrantLock 提供了更多的灵活性,例如可中断锁、非块结构的锁等。
综上,Synchronized 和 ReentrantLock 在可重入性、获取锁方式、可中断性、公平性和性能等方面有所区别。在选择使用哪种机制时,需要根据具体的情况综合考虑。一般而言,对于简单的同步需求,使用 Synchronized 更为方便;而对于更复杂的同步需求,可以考虑使用 ReentrantLock 提供的额外功能。
Reentlock的底层实现和AQS有啥关系?
答了乐观锁,我的无知再次暴露无遗(❌,我不知道AQS是啥啊。。)
AQS(AbstractQueuedSynchronizer),抽象队列同步器
核心思想:
如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
JVM内存模型是什么样的?
线程私有:PC 、虚拟方法栈、本地方法栈
公有:堆 永久代(java8前)、元数据区(java8后)
元数据区存的是什么?
元空间中有常量池、类的配置信息(⚠️说得好像有问题,复盘)
元空间的实现称为常量池
常量池中存储了以下几种元数据:
1.类信息(Class Information):包括类的名称、父类、接口、访问修饰符等。
2.字段信息(Field Information):包括字段的名称、类型、访问修饰符等。
3.方法信息(Method Information):包括方法的名称、参数类型、返回类型、访问修饰符等。
4.字符串常量(String Constants):包括字符串字面值,例如 "Hello, World!"。
5.字面常量(Literal Constants):包括整数、浮点数、布尔值等字面常量。
类加载机制是怎么样的?
(不太熟练)
首先读取类的信息
再进行安全性检查
开辟虚拟内存空间,进行静态变量的初始化
将虚拟地址变为物理地址
再执行构造函数
加载
验证
准备
解析
初始化
使用
双亲委派是什么?
从最早的祖先开始判断能否加载需要的类
子类加载器如果没有加载过该目标类,就先委托父类加载器加载该目标类,只有在父类加载器找不到字节码文件的情况下才从自己的类路径中查找并装载目标类。
保证Java程序的稳定运行,避免类的重复加载:JVM区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类
追问:父类怎么知道他能不能加载需要的类?
(❌,不了解,一个比较好的问题)
其实很简单:
始祖类加载器判断是否加载过该Class,如果已加载,则返回Class对象
如果没有则尝试从其对应的类路径下寻找class字节码文件并载入(有空去看看源码)
如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的子类加载器
算法:二叉树,找两个随机节点的最近公共父节点
用递归做更好
38
1
分享
操作
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
