Quellcode durchsuchen

修改了面经的文档

seamew vor 1 Jahr
Ursprung
Commit
9005d11e99

BIN
面经/问答/assets/image-20230511103843026.png


BIN
面经/问答/assets/image-20230511103924803.png


BIN
面经/问答/assets/image-20230511103937416.png


+ 15 - 17
面经/问答/并发编程.md

@@ -1,25 +1,25 @@
 ## 为什么wait和notify必须放在synchronized中?
 
-在Java中,wait()和notify()是Object类的两个方法,它们用于实现线程间的协作。wait()使一个线程进入等待状态,直到另一个线程发出通知唤醒它。而notify()则用于唤醒正在等待的线程。
+在Java中,`wait()``notify()``Object`类的两个方法,它们用于实现线程间的协作。`wait()`使一个线程进入等待状态,直到另一个线程发出通知唤醒它。而notify()则用于唤醒正在等待的线程。
 
-wait()和notify()必须放在synchronized块中是因为这些方法依赖于对象的监视器锁(也称为互斥锁)。只有获得了对象的监视器锁(该锁即为调用wait方法的对象)的线程才能调用wait()和notify()方法。如果这些方法不在同步块中使用,就无法保证线程安全性。
+`wait()``notify()`必须放在`synchronized`块中是因为这些方法依赖于对象的监视器锁(也称为互斥锁)。只有获得了对象的监视器锁(该锁即为调用`wait`方法的对象)的线程才能调用`wait()``notify()`方法。如果这些方法不在同步块中使用,就无法保证线程安全性。
 
-当一个线程调用wait()方法时,它会释放持有的锁并进入等待状态,等待其他线程调用notify()方法来唤醒它。如果wait()方法不在同步块中使用,那么该线程在释放锁之后可能已经被其他线程修改了。这样,即使其他线程调用了notify()方法唤醒了它,该线程也无法正确地处理唤醒事件。
+当一个线程调用`wait()`方法时,它会释放持有的锁并进入等待状态,等待其他线程调用`notify()`方法来唤醒它。如果`wait()`方法不在同步块中使用,那么该线程在释放锁之后可能已经被其他线程修改了。这样,即使其他线程调用了`notify()`方法唤醒了它,该线程也无法正确地处理唤醒事件。
 
-同样,notify()方法也必须在同步块中使用。如果一个线程在未获得锁的情况下调用notify()方法,那么它将无法通知任何等待的线程。因为它没有获取锁,所以它不能访问共享数据或执行必要的同步操作来确保正确的通知。
+同样,`notify()`方法也必须在同步块中使用。如果一个线程在未获得锁的情况下调用`notify()`方法,那么它将无法通知任何等待的线程。因为它没有获取锁,所以它不能访问共享数据或执行必要的同步操作来确保正确的通知。
 
-因此,使用wait()和notify()方法时,必须在同步块中使用它们,以确保线程之间的安全性并避免出现竞态条件。
+因此,使用`wait()``notify()`方法时,必须在同步块中使用它们,以确保线程之间的安全性并避免出现竞态条件。
 
 ## volatile 关键字
 
-在Java中,volatile关键字是用于保证多线程环境下变量的可见性和有序性。
+在Java中,`volatile`关键字是用于保证多线程环境下变量的可见性和有序性。
 
-1. 保证变量可见性:被volatile关键字声明代表变量是共享且不稳定的,每次使用它都到主存中进行读取,并且强制刷新到内存。
-2. 保证变量有序性:JVM 具有指令重排的特性,可以保证程序执行效率更高,但是volatile关键字会进制指令重排保证其有序性。
+1. 保证变量可见性:被`volatile`关键字声明代表变量是共享且不稳定的,每次使用它都到主存中进行读取,并且强制刷新到内存。
+2. 保证变量有序性:JVM 具有指令重排的特性,可以保证程序执行效率更高,但是`volatile`关键字会禁止指令重排保证其有序性。
 
 ## volatile 关键字底层原理
 
-`volatile`是通过编译器在生成字节码时,在指令序列中添加**内存屏障**来保证变量可见性。
+`volatile`是通过编译器在生成字节码时,在指令序列中添加**内存屏障**来保证变量可见性。
 
 JMM层面的“**内存屏障**”:
 
@@ -38,15 +38,15 @@ JVM的实现会在volatile读写前后均加上内存屏障,在一定程度上
 > **volatile 写操作**
 > **StoreLoad**
 
-**禁止指令重排,汇编层面**
+禁止指令重排,汇编层面
 
->  **lock 前缀**:lock不是内存屏障,而是一种锁。执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU
+>  **lock 前缀:lock不是内存屏障,而是一种锁。执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU**
 
 ## synchronized 关键字
 
 `synchronized` 是 Java 中的一个关键字,翻译成中文是同步的意思,主要解决的是多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。
 
-在JDK1.6之前synchronized关键字基于操作系统mutux互斥变量实现,该操作较为重量级,但是在JDK1.6之后进行的JVM层面的锁优化。效率大大提升,优化后的锁主要分为一下四类
+在JDK1.6之前`synchronized`关键字基于操作系统`mutux`互斥变量实现,该操作较为重量级,但是在JDK1.6之后进行的JVM层面的锁优化。效率大大提升,优化后的锁主要分为一下四类
 
 1. 无锁状态
 2. 偏向锁状态
@@ -63,11 +63,11 @@ JVM的实现会在volatile读写前后均加上内存屏障,在一定程度上
 
 * `volatile` 关键字是线程同步的轻量级实现,所以性能肯定比`synchronized`关键字要好 。
 
-* `volatile` 关键字只能用于变量而 `synchronized` 关键字可以修饰方法以及代码块 。
+* `volatile` 关键字只能用于变量而 `synchronized` 关键字可以修饰方法以及代码块 。
 
-* `volatile` 关键字能保证数据的可见性,但不能保证数据的原子性。`synchronized` 关键字两者都能保证。
+* `volatile` 关键字能保证数据的可见性。`synchronized` 关键字能保证数据原子性
 
-* `volatile`关键字主要用于解决变量在多个线程之间的可见性,而 `synchronized` 关键字解决的是多个线程之间访问资源的同步性。
+* `volatile` 关键字主要用于解决变量在多个线程之间的可见性,而 `synchronized` 关键字解决的是多个线程之间访问资源的同步性。
 
 ## ReentrantLock锁
 
@@ -158,8 +158,6 @@ AQS提供了一种通用的框架,用于实现线程间的协作和同步操
 * **`ThreadPoolExecutor.DiscardPolicy`:** 不处理新任务,直接丢弃掉。
 * **`ThreadPoolExecutor.DiscardOldestPolicy`:** 此策略将丢弃最早的未处理的任务请求。
 
-我们这里使用自定义的饱和策略,即为新建一个线程去处理饱和任务
-
 ### 如何设定线程池的大小?
 
 * **CPU 密集型任务(N+1)**

+ 45 - 8
面经/问答/计网.md

@@ -37,6 +37,12 @@ TCP 是**面向连接的、可靠的、基于字节流**的传输层通信协议
 
 ## TCP和UDP区别
 
+连接 服务对象
+
+可靠性 拥塞控制、流量控制 
+
+头部长度不同 分片不同
+
 1. 连接
 
 - TCP 是面向连接的传输层协议,传输数据前先要建立连接。
@@ -62,12 +68,7 @@ TCP 是**面向连接的、可靠的、基于字节流**的传输层通信协议
 - TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 `20` 个字节,如果使用了「选项」字段则会变长的。
 - UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
 
-6. 传输方式
-
-- TCP 是流式传输,没有边界,但保证顺序和可靠。
-- UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
-
-7. 分片不同
+6. 分片不同
 
 - TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
 - UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
@@ -201,6 +202,8 @@ TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存
 - 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
 - 保证「被动关闭连接」的一方,能被正确的关闭;
 
+**等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。**
+
 ## TIME_WAIT 过多有什么危害?
 
 - 第一是占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等;
@@ -216,7 +219,7 @@ TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存
 
 答案是可以
 
-> 什么是 TCP 延迟确认机制?
+> **什么是 TCP 延迟确认机制?**
 
 当发送没有携带数据的 ACK,它的网络效率也是很低的,因为它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报文。 为了解决 ACK 传输效率低问题,所以就衍生出了 **TCP 延迟确认**。 TCP 延迟确认的策略:
 
@@ -254,7 +257,7 @@ TCP 的 Keepalive 这东西其实就是 **TCP 的保活机制**
 - 特殊字符作为边界:我们可以在两个用户消息之间插入一个特殊的字符串,这样接收方在接收数据时,读到了这个特殊字符,就把认为已经读完一个完整的消息。
 - 自定义消息结构:我们可以自定义一个消息结构,由包头和数据组成,其中包头包是固定大小的,而且包头里有一个字段来说明紧随其后的数据有多大。
 
-## 从输入 URL 到页面展示到底发生了什么?(非常重要)
+## 从输入 URL 到页面展示到底发生了什么?
 
 总体来说分为以下几个过程:
 
@@ -264,3 +267,37 @@ TCP 的 Keepalive 这东西其实就是 **TCP 的保活机制**
 4. 服务器处理请求并返回HTTP报文
 5. 浏览器解析渲染页面
 6. 连接结束
+
+## OSI 七层模型
+
+![image-20230511103843026](assets/image-20230511103843026.png)
+
+## TCP/IP 四层模型
+
+**TCP/IP 四层模型** 是目前被广泛采用的一种模型,我们可以将 TCP / IP 模型看作是 OSI 七层模型的精简版本,由以下 4 层组成:
+
+1. 应用层
+2. 传输层
+3. 网络层
+4. 网络接口层
+
+![image-20230511103924803](assets/image-20230511103924803.png)
+
+每一层的封装格式:
+
+![image-20230511103937416](assets/image-20230511103937416.png)
+
+##  既然有 HTTP 协议,为什么还要有 WebSocket?
+
+* TCP 协议本身是**全双工**的,但我们最常用的 HTTP/1.1,虽然是基于 TCP 的协议,但它是**半双工**的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的 WebSocket 协议。
+* nginx默认超时时间是60S,所以websocket要采取ping/pong方式保证连接的活性
+
+## websocket的长连接与http的keep-alive的区别
+
+WebSocket 和 HTTP 协议都是基于 TCP 连接实现的,但是它们的长连接机制有一些区别。
+
+HTTP 长连接通常使用 HTTP/1.1 中的 "keep-alive" 机制,在客户端和服务器之间完成一次请求/响应后,会继续使用已建立的 TCP 连接来发送和接收多个请求/响应。这种方式可以减少频繁地建立、断开 TCP 连接所带来的性能开销,从而提高网络传输效率。但是,使用 HTTP 长连接时,客户端和服务器之间的通信仍然需要按照请求-响应模式进行,且无法实现即时通信和实时数据传输。
+
+WebSocket 的长连接是指在服务器和客户端之间建立一条持久的双向通信通道,该通道会一直保持打开状态,直到显示地关闭。这种连接不仅可以支持即时通信和实时数据传输,而且可以使得服务器可以主动向客户端推送消息,从而实现更高效的数据传输和通信。此外,WebSocket 还有一个心跳检测机制(即“ping/pong”),用于检测连接是否处于活动状态,并保证连接的稳定性。
+
+综上所述,HTTP 的长连接主要是为了减少建立和断开连接所带来的性能开销,而 WebSocket 的长连接则是为了支持实时通信和实时数据传输,并保持连接的稳定性。此外,WebSocket 通过心跳检测机制可以更好地保护长连接,而 HTTP 长连接则没有这个机制。