八股背诵记录二

八股背诵(二)

第二天



第二天


1.三次握手的过程,为什么是三次?

TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手来进行的。三次握手过程如下图
TCP三次握手

  • 一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态
  • 客户端会随机初始化序号(client_isn),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN 标志位置为 1,表示 SYN 报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
  • 服务端收到客户端的 SYN 报文后,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。
  • 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次「确认应答号」字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态。
  • 服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。

从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的,这也是面试常问的题。
一旦完成三次握手,双方都处于 ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。

为什么是三次握手?不是两次、四次?

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)
  • 三次握手才可以同步双方的初始序列号
  • 三次握手才可以避免资源浪费

TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

不使用「两次握手」和「四次握手」的原因:
「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

2.四次挥手的过程,为什么是四次?

TCP 断开连接是通过四次挥手方式。双方都可以主动断开连接,断开连接后主机中的「资源」将被释放,四次挥手的过程如下图:
TCP四次挥手

  • 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入FIN_WAIT_1 状态。
  • 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSE_WAIT 状态。
  • 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
  • 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
  • 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
  • 服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
  • 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态。

为什么需要四次挥手?

回顾下四次挥手双方发 FIN 包的过程,就能理解为什么需要四次了。

  • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。

从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,因此是需要四次挥手。

3.http的Keep-Alive是什么?Tcp的Keepalive和http的Keep-Alive是一个东西吗?

Keep-Alive是什么?

HTTP1.0中需要配置长连接,在请求头中配置 connection:keep-A1ive,而HTTP1.1中默认开启了长连接

Keep-Alive 是一种 HTTP 协议的机制,也被称为 HTTP长连接

在启用 Keep-alive 的情况下,客户端和服务器在完成一个 HTTP 请求和响应后,并不立即关闭连接,而是继续保持连接处于打开状态。在连接保持打开的情况下,客户端可以继续发送其他请求,服务器可以继续发送响应,而无需重新建立连接,减少了连接的建立和关闭的开销,从而提高性能和效率。

Keep-Alive的优缺点

  1. 优点:
    TCP 连接的建立和关闭需要时间和资源,通过保持连接打开,可以减少这些开销,从而提高性能和效率客户端可以在同一个连接上同时发送多个请求,服务器可以并行地处理这些请求,提高并发性能。Keep-alive 连接中的多个请求共享同一个连接的头部信息(如用户代理、Cookie 等),减少了头部信息的重复传输。
  2. 缺点:
    长时间的持久连接可能会占用服务器资源,特别是在高并发的情况下。为了平衡资源利用和性能,服务器和客户端通常会设置 Keep-alive 的超时时间,以便在一段时间内保持连接打开,超过该时间则关闭连接。

TCP KeepAlive是什么

TCP keep-Alive 是在操作系统和网络协议栈级别实现的,它通过发送特定的探测数据包来维护连接的活跃性。

  1. 在启用 TCP Keep-Aive 的情况下,操作系统会定期发送一些特定的探测数据包到连接的另一端。这些数据包通常是空的,没有实际的数据内容。
  2. 如果一端收到了探测数据包,它会回复一个确认ACK)数据包。如果一段时间内没有收到确认数据包,发送端将认为连接可能已经断开,从而触发连接关闭。
  3. TCP Keep-Alive 的主要目的是检测连接是否处于空闲状态,即没有实际数据传输。它不仅可以检测到连接断开,还可以在空闲连接超过一定时间时释放连接,从而释放资源。

TCP的TCP 的Keepalive 和 HTTP 的 Keep-Alive 是一个东西吗?

  1. HTTP 的 Keep-Alive,是由应用层实现的,称为 HTTP 长连接
    每次请求都要经历这样的过程:建立 TCP ·>请求资源 ->响应资源 ->释放连接,这就是HTTP短连接,但是这样每次建立连接都只能请求一次资源,所以HTTP 的 keep-Alive 实现了使用同一个 TCP 连接来发送和接收多个 HTTP请求/应答,避免了连接建立和释放的开销,就就是 HTTP 长连接。
  2. TCP 的 Keepalive,是由TCP 层(内核态)实现的,称为 TCP 保活机制,是一种用于在 TCP 连接上检测空闲连接状态的机制
    通俗地说,就是TCP有一个定时任务做倒计时,超时后会触发任务,内容是发送一个探测报文给对端,用来判断对端是否存活。

4.DNS查询过程

DNS查询

  1. 先查询浏览器缓存是否有该域名对应的IP地址。
  2. 如果浏览器缓存中没有,会去计算机本地的Host文件中查询是否有对应的缓存。
  3. 如果Host文件中也没有则会向本地的DNS服务器(通常由你的互联网服务提供商(ISP)提供,比如中国移动)发送一个DNS查询请求。
  4. 如果本地DNS解析器有该域名的ip地址,就会直接返回,如果没有缓存该域名的解析记录,它会向根DNS服务器发出查询请求。根DNS服务器并不负责解析域名,但它能告诉本地DNS解析器应该向哪个顶级域(.com/.net/.org)的DNS服务器继续查询。
  5. 本地DNS解析器接着向指定的顶级域名DNS服务器发出查询请求。顶级域DNS服务器也不负责具体的域名解口析,但它能告诉本地DNS解析器应该前往哪个权威DNS服务器查询下一步的信息。
  6. 本地DNS解析器最后向权威DNS服务器发送查询请求。权威DNS服务器是负责存储特定域名和IP地址映射的6.服务器。当权威DNS服务器收到查询请求时,它会查找"example.com"域名对应的IP地址,并将结果返回给本地DNS解析器。
  7. 本地DNS解析器将收到的IP地址返回给浏览器,并且还会将域名解析结果缓存在本地,以便下次访问时更快地响应。
  8. 浏览器发起连接: 本地DNS解析器已经将IP地址返回给您的计算机,您的浏览器可以使用该IP地址与目标服务器建立连接,开始获取网页内容,

5.CDN是什么?

CDN,全称为内容分发网络(contentDelivery Network),过将内容存储在分布式的服务器上,使用户可以从距离较近的服务器获取所需的内容,从而减少数据传输的时间和距离,提高内容的传输速度、减少延迟和提升用户体验。

CDN的工作流程

  • 1.当用户输入一个域名或点击一个链接时,首先会进行域名解析。如果网站启用了 CDN,DNS 解析会返回距离用户最近的 CDN 节点的 IP 地址,而不是原始源服务器的 IP 地址。
  • 2.用户的请求会被路由到距离最近的 CDN 节点,并且CDN 节点可以根据服务器的负载和可用性,动态地将请求分发到最适合的服务器节点上。
  • 3.CDN 会首先检查是否已经缓存了该资源。如果有缓存,CDN 节点会直接返回缓存的资源,如果没有缓存所需资源,它会从源服务器(原始服务器)回源获取资源,并将资源缓存到节点中,以便以后的请求。

6.Cookie和Session是什么?有什么区别?

cookiesession 都用于管理用户的状态和身份,cookie 通过在客户端记录信息确定用户身份,session 通过在服务器端记录信息确定用户身份。
1.Cookie

  • Cookie 是存储在用户浏览器中的小型文本文件,用于在用户和服务器之间传递数据。通常,服务器会将一个或多个 Cookie 发送到用户浏览器,然后浏览器将这些 Cookie 存储在本地。服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。

2.Session

  • 客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是session。Session 主要用于维护用户登录状态、存储用户的临时数据和上下文信息等。

二者区别

  • 存储位置:Cookie 数据存储在用户的浏览器中,而 Session 数据存储在服务器上。
  • 数据容量:Cookie 存储容量较小,一般为几 KB。Session 存储容量较大,通常没有固定限制,取决于服务器的配置和资源。
  • 安全性:由于 Cookie 存储在用户浏览器中,因此可以被用户读取和篡改。相比之下,Session 数据存储在服务器上,更难被用户访问和修改。
  • 传输方式:Cookie 在每次 HTTP 请求中都会被自动发送到服务器,而 SessionID 通常通过 Cookie 或 URL 参数传递。

7.进程和线程的区别

线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进程都有若干个线程,至少包含一个线程。

根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位

资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的

影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。

执行过程:每个独立的进程有程序运行的入口. 顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

8.并行和并发有什么区别

  • 单个处理核在很短时间内分别执行多个进程,称为并发
  • 多个处理核同时执行多个进程称为并行

对于并发来说,CPU需要从一个进程切换到另一个进程,在切换前必须要记录当前进程中运行的状态信息,以备下次切换回来的时候可以恢复执行。

9.解释一下用户态和核心态

用户态和内核态是操作系统为了保护系统资源和实现权限控制而设计的两种不同的CPU运行级别,可以控制进程或程序对计算机硬件资源的访问权限和操作范围。

  • 用户态:在用户态下,进程或程序只能访问受限的资源和执行受限的指令集,不能直接访问操作系统的核心部分,也不能直接访问硬件资源。
  • 核心态:核心态是操作系统的特权级别,允许进程或程序执行特权指令和访问操作系统的核心部分。在核心态下,进程可以直接访问硬件资源,执行系统调用,管理内存、文件系统等操作。

10.进程调度算法你了解多少?

  • 先来先服务(FCFS)调度算法

FCFS是一种最简单的调度算法,它既可以用于作业的调度,又可以用于进程调度。在作业调度中,算法每次从后备作业队列中选择最先进入该队列的一个或几个作业,将他们调入内存,分配必要的资源,创建进程并放入就绪队列。
在进程调度中,FCFS调度算法每次从就绪队列中选择最先进入该队列的进程,将处理机分噢诶给它,使之投入运行,直到完成或尹某种原因而阻塞时才释放处理机。
FCFS属于不可剥夺(抢占)算法。从表面上看,它对所有作业都是公平的,但是如果有一个长作业先到达系统,就会使后面许多短作业等待很长时间,因此这种方法肯定不能作为分时系统和实时系统的调度方法,但是它常被结合在其他调度策略使用。比如在使用优先级作为调度策略的系统中,往往对多个具有相同优先级的进程按FCFS原则处理。
· 特点分析:算法简单,但是效率低下;对长作业较为有利,对短作业不利;利于CPU繁忙型作业,不利于I/O繁忙型作业。

  • 短作业优先(SJF)调度算法

短作业(进程)优先调度算法是指对短作业(进程)优先调度算法。短作业优先调度算法从后备队列中选择一个或若干估计运行时间最短的作业,将它们调入内存运行;短进程优先(SPF)调度算法是从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即指向,直到完成或发生某时间而阻塞时,才释放处理机。
但是这种算法有着不容忽视的缺点:
①该算法对长作业不利,SJF中长作业的周转时间会增加。更糟的是,若一旦有长作业进入系统的后备队列,由于调度程序总是优先调度那些短作业(即使是后来的短作业也会被优先安排给处理机),导致长作业长期不被调度,饿死在后备队列中。
②完全没有考虑作业的紧迫程度,因而不能保证紧迫的作业会被及时处理。
③由于作业的长短只是根据用户所提供的预估的执行时间而定的,而用户又可能会有意无意地缩短其作业的估计运行时间,使得算法不一定能真正做到短作业优先调度。
但这算法的优点也显而易见:平均等待时间、平均周转时间最少。

  • 优先级调度算法

又称优先权调度算法,它既可以用于作业调度,又可用于进程调度。该算法的优先级用于描述作业运行的紧迫程度。
在作业调度中,优先级调度算法每次从后备作业队列中选择优先级最该的一个或几个作业,将他们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中,优先级调度算法每次从就绪队列中选择优先级最高的进程,并分配处理机,运行。
根据新的更高的优先级进程能否抢占正在执行的进程,可将该调度算法分为如下两种:
①非剥夺(抢占)式优先级调度算法:当一个进程正在处理机上运行时,即使有某个更在重要或者紧迫的进程进入就绪队列,仍然让正在运行的进程继续运行,直到由于自身的原因而主动让出处理机时(任务完成或等待),才把处理机分配给更重要或紧迫的进程。
②剥夺式优先级调度算法:当一个进程正在处理机上运行,若有某个更为重要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。
而根据进程创建后其优先级是否可以改变,可以将进程优先级分为一下两种:
①静态优先级:优先级是在创建进程时确定的,并且进程的整个运行期间保持不变。确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
②动态优先级:在进程运行过程中,根据进程情况的变化动态调整优先级。动态调整优先级的主要依据有进程占有CPU的时间的长短、就绪进程等待CPU时间的长短。
一般来说,进程优先级可以参考一下原则:
①系统进程>用户进程。
②交互型进程>非交互型进程(前台进程>后台进程)
③I/O型进程>计算型进程。

  • 高响应比优先调度算法

主要用于作业调度,是对FCFS调度算法和SJF调度算法的一种综合平衡,同时考虑了每个作业的等待时间和估计的运行时间。在每次进行作业调度时,先计算后备队列中每个作业的响应比,从中选出响应比最高的作业投入运行。
响应比的变化规律可描述为:
响应比Rp = (等待时间+要求服务时间)/要求服务时间
根据公式可知:
①作业的等待时间相同时,要求服务时间约旦,响应比越高,有利于短作业。
②要求服务时间相同时,作业的响应比由其等待时间决定,等待时间越长,其响应比越高,因而它实现的是先来先服务。
③对于长作业,作业的响应比可以随等待时间的增加而提高,等待时间足够长时,其响应比便可升到很高,从而可以获得处理机,不会饿死。

  • 时间片轮转调度算法

时间片轮转调度算法主要适用于分时系统。在这种算法中,系统将所有就绪进程按到达时间的先后次序排成一个队列,进程调度程序总是选择就绪队列中的第一个进程执行,即先来先服务的原则,但是仅能运行一个时间片。在使用完一个时间片后,即使进程并未完成其运行,它也必须释放出(被抢占)处理机给下一个就绪的进程,而被抢占的进程返回到就绪队列的末尾重新排队,等候再次运行。
在时间片轮转的调度算法中,时间片的大小对系统性能有很大影响。如果时间片足够大,以至于所以进程都能在一个事件内执行完毕,则时间片轮转调度算法就退化成FCFS算法。如果时间片很小,则处理机将在进程间过于频繁地切换,使得处理机开销增大,而真正用于运行用户进程的时间将减少。因此,时间片的选择要适当,可以根据系统响应时间、就绪队列中的进程数目和系统的处理能力等决定。

  • 多级反馈队列调度算法

多级反馈队列调度算法是时间片轮转算法和优先级调度算法的综合与发展。通过动态调整进程优先级和时间片的大小,多级反馈队列调度算法可以兼顾多方面的系统目标。例如,为了提高系统吞吐量和缩短平均周转时间而照顾短进程;为了获得较好的I/O设备利用率和缩短响应时间而照顾I/O型进程;同时,也不必实现估计进程的执行时间。

多级反馈队列调度算法的实现思想如下:
(1)设置多个就绪队列,并为各个队列赋予不同的优先级,第一级队列的优先级最高,第二级队列次之,其余队列的优先级逐次降低。
(2)赋予各个队列中进程执行时间片的大小各不相同。在优先级越高的队列中,每个进程的运行时间片越小。例如,第二级队列的时间片要比第一级队列的时间片长一倍…第i+1级队列的时间片要比第i级队列的时间片长一倍。
(3)当一个新的进程进入内存后,首先将它放入第一级队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时候,如果它能在时间片内完成,便可准备撤离系统;若它在一个时间片结束时尚未完成,调度程序便将该进程转入第二级末尾,再同样按FCFS原则等待调度执行;若它在第二级队列中运行一个时间片后仍未完成,再以同样的方法进入第三级队列…如此下去,当一个长进程从第一级队列一次降到第n级队列后,在第n级队列中便采用时间片轮转方式进行。
(4)仅当第一级队列为空时,调度程序才调度第二级队列中的进程进行;仅当第1到(i-1)级队列均为空,才会调度第i级队列中的进程运行。若处理机正在执行第i级队列中的某个进程,此时又有新的进程进入优先级较高的队列[第1到(i-1)级的任意一级],则此时行进程将抢占正在运行的处理机,即由调度程序把正在运行的进程放回第i级队列末尾,把处理机分配给新到的更高优先级进程。

这种调度方法优势如下:
(1)终端型作业用户:短作业优先。
(2)短批处理作业用户:周转时间较短。
(3)长批处理作业用户:经过前面几个队列得到部分执行,不会饿死。

11.进程间有哪些通信方式?

  1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  3. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  4. 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
  5. 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  6. 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
  7. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

12.解释一下进程同步和互斥,以及如何实现进程同步和互

链接:https://blog.csdn.net/Shangxingya/article/details/113799732

13.什么是死锁?如何预防死锁?

死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。

  1. 系统资源的竞争

系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。

  1. 进程运行推进顺序不合适

进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。

三:产生死锁的四个必要条件:
(1)互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。

(2)请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

(3)不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。

(4)循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

四:死锁的避免与预防:
只要破坏产生死锁的四个条件中的其中一个就可以了

  • 破坏互斥条件 这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)
  • 破坏请求与保 持条件 一次性申请所有的资源。
  • 破坏不剥夺条件 占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
  • 破坏循环等待条件 靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
  • 锁排序法:(必须回答出来的点) 指定获取锁的顺序,比如某个线程只有获得A锁和B锁,才能对某资源进行操作,在多线程条件下,如何避免死锁? 通过指定锁的获取顺序,比如规定,只有获得A锁的线程才有资格获取B锁,按顺序获取锁就可以避免死锁。这通常被认为是解决死锁很好的一种方法。
  • 使用显式锁中的ReentrantLock.try(long,TimeUnit)来申请锁

14.介绍一下几种典型的锁

  • 读写锁
    多个读者可以同时进行读
    写者必须互斥(只允许一个写者写,也不能读者写者同时进行)
    写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)
  • 互斥锁
    一次只能一个线程拥有互斥锁,其他线程只有等待
    互斥锁是在抢锁失败的情况下主动放弃CPU进入睡眠状态直到锁的状态改变时再唤醒,而操作系统负责线程调度,为了实现锁的状态发生改变时唤醒阻塞的线程或者进程,需要把锁交给操作系统管理,所以互斥锁在加锁操作时涉及上下文的切换。互斥锁实际的效率还是可以让人接受的,加锁的时间大概100ns左右,而实际上互斥锁的一种可能的实现是先自旋一段时间,当自旋的时间超过阀值之后再将线程投入睡眠中,因此在并发运算中使用互斥锁(每次占用锁的时间很短)的效果可能不亚于使用自旋锁
  • 条件变量
    互斥锁一个明显的缺点是他只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,他常和互斥锁一起使用,以免出现竞态条件。当条件不满足时,线程往往解开相应的互斥锁并阻塞线程然后等待条件发生变化。一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。总的来说互斥锁是线程间互斥的机制,条件变量则是同步机制。
  • 自旋锁
    如果进线程无法取得锁,进线程不会立刻放弃CPU时间片,而是一直循环尝试获取锁,直到获取为止。如果别的线程长时期占有锁那么自旋就是在浪费CPU做无用功,但是自旋锁一般应用于加锁时间很短的场景,这个时候效率比较高。

15.讲一讲你理解的虚拟内存

虚拟内存是一种内存管理技术,它允许计算机系统通过硬盘空间扩展其物理内存容量。这项技术的核心在于,它为每个运行中的程序提供了一个庞大的、连续的虚拟地址空间,而实际上,这个空间可能被分散存储在物理内存和硬盘上。

局部性原理是虚拟内存的理论基础。大多数程序展现出时间局部性和空间局部性,如果执行了

程序的某条指令,那么在不久之后这条指令很可能再次执行

一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很可能被访问

虚拟内存利用这些原理,通过预加载可能被访问的数据到物理内存中,从而减少访问延迟。

在多任务处理方面,虚拟内存确保了每个进程都拥有独立的地址空间,互不干扰。同时,它通过内存保护机制,防止了进程间的非法内存访问,增强了系统的稳定性和安全性。

虚拟内存的实现依赖于几个关键部分,包括内存分页页表页面置换算法。操作系统将虚拟内存划分为固定大小的页,并使用页表来跟踪虚拟页和物理页之间的映射关系。当物理内存不足时,操作系统会根据页面置换算法,如最近最少使用(LRU)算法,决定哪些页应该被交换到硬盘上。

然而,虚拟内存并非没有性能影响。页面置换可能会引入额外的延迟,因为从硬盘加载数据到内存需要时间。因此,优化页面置换策略和内存分配是提高系统性能的关键

16.你知道的线程同步方式有哪些?

线程同步是指在多个线程并发执行时,保证它们按照一定的顺序执行以达到正确的结果。
常用的线程同步机制有以下几种:

  • 互斥锁:使用互斥锁(Mutex)可以保证在同一时间只有一个线程可以访问共享资源。当一个线程获得了互斥锁后,其他线程需要等待该线程释放锁才能继续访问共享资源。
  • 信号量:信号量(Semaphore)是一种计数器,用来控制同时访问某个共享资源的线程数量。当计数器大于0时,线程可以访问资源并将计数器减1;当计数器等于0时,线程需要等待其他线程释放资源后才能继续访问。
  • 条件变量:条件变量(Condition Variable)用于线程之间的通信和协调。一个线程可以等待某个条件的发生,而另一个线程可以在满足条件时通知等待的线程继续执行。
  • 读写锁:读写锁(Read-Write Lock)允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这样可以提高读取操作的并发性,同时保证写入操作的原子性。
  • 原子操作:原子操作是一种不可中断的操作,要么全部执行成功,要么全部不执行。原子操作可以保证多个线程同时访问共享资源时的数据一致性。
  • 屏障:屏障(Barrier)用于线程之间的同步,它可以让一组线程在某个点上等待,直到所有线程都到达这个点后再继续执行。

17.有哪些页面置换算法

  • 先进先出(FIFO)算法:将最早进入内存的页面替换出去。
  • 最近最少使用(LRU)算法:将最近最少被访问的页面替换出去。
  • 最不常用(LFU)算法:将最不经常被访问的页面替换出去。
  • 时钟置换算法:通过一个指针按照顺时针方向遍历页面,当需要替换页面时,替换指针指向的页面,并将该页面的访问位清零。
Python是一种简洁而强大的编程语言,为了更好地掌握Python编程,有一些常见的知识点和技巧是需要背诵的,我们将其称为“Python八股文”。下面是这些知识点和技巧的简要概述: 1. 变量与数据类型:掌握Python的基本数据类型,例如整数、浮点数、字符串和布尔值,并学会如何声明和使用变量。 2. 条件语句与循环:了解条件语句(如if-else语句)和循环语句(如for循环和while循环)的用法,以便实现不同的控制流程。 3. 列表和字典:熟悉Python中的列表和字典数据结构,并掌握它们的基本操作方法,如访问、添加、删除和修改元素。 4. 函数与模块:理解函数和模块的概念,学会如何定义和调用函数,并了解如何导入和使用模块。 5. 文件操作:掌握读取和写入文件的基本方法,包括打开文件、读取内容、写入内容和关闭文件。 6. 异常处理:了解异常处理的概念和用法,以便在程序出现错误时进行适当的处理。 7. 面向对象编程:理解面向对象编程的基本概念,包括类、对象、属性和方法,并学会如何定义和使用类。 8. 正则表达式:掌握正则表达式的基本语法,用于处理和匹配文本数据。 以上是Python八股文的概要内容。通过背诵和实践,掌握这些知识点和技巧,将能够更加熟练地使用Python进行编程,并能够解决各种实际问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值