java面试复习重点,面试必备(起源来自CS-NOTES)

本文来自CS-NOTES

https://cyc2018.github.io/CS-Notes/#/

面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力。但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点。

本文虽然来自CS-NOTES中,但是觉得里面有些地方解释的不够清楚,不够通俗易懂,所以写了本篇文章。

另外再附赠一份java面试题以及答案,内容也还不错,偏向于java基础。

链接:https://pan.baidu.com/s/1Ff7cP5xAll4jtbS3OTkmqA 
提取码:ka1n

首先是九大复习重点

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


1. 算法

1.排序:大部分要求能手写,并分析时间空间复杂度,以及稳定性。

2.树:红黑树的原理以及再JDK中的使用。B+树以及在数据库索引中的使用。

红黑树:在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。(见算法符号表)

3.图:拓扑排序,并查集。最短路径。最小生成树。

4.散列表:实现原理,以及在JDK中的使用。

5.字符串:KMP。AC自动机。Trie树。

2. 操作系统

2.1 基础

  • ★★★ 进程与线程的本质区别、以及各自的使用场景。

什么是线程?线程是进程内部的一个执行流,也就是线程在进程的地址空间内运行,一个进程内的所有线程共享进程资源。创建,销毁一个线程相较创建,销毁一个进程成本要低。线程间的切换相比于进程间的切换容易的多。

什么是进程?进程是拥有一个执行流,或多个执行流的线程组。进程是一个能独立运行的基本单位,同时也是系统分配资源基本单位。进程间的相互制约,进程具有执行的间断性,进程按照各自独立不可预知的速度向前推进。

举例:比如电脑的资源管理器,ctrl+alt+点,可以打开任务管理器,里面有一个进程选项,下面会有若干个进程,每一个进程里面会有多个线程同时为这个进程工作。每一个进程都是独立的,进程不是同时进行的,只不过计算机在进行进程间的快速切换,切换的速度很快,让你以为就是各个进程是同时进行的。

进程间独立,线程间共享。

线程的应用场景:等待慢速I/O时,交给一个线程等待,接着做其他事情。通信,比较容易(注意加锁)

进程的应用场景:需要安全稳定时用进程,需要速度时用进程,既要速度又要安全。


其实吧,压力也没有那么大!


  • ★★★ 进程调度算法的特点以及使用场景。

不同环境的调度算法目标不同,因此需要针对不同环境来讨论调度算法。

1. 批处理系统

批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。

1.1 先来先服务 first-come first-serverd(FCFS)

非抢占式的调度算法,按照请求的顺序进行调度。

有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。

总而言之,利长不利短

1.2 短作业优先 shortest job first(SJF)

非抢占式的调度算法,按估计运行时间最短的顺序进行调度。

长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。

总而言之,利短不利长。

1.3 最短剩余时间优先 shortest remaining time next(SRTN)

最短作业优先的抢占式版本,按剩余运行时间的顺序进行调度。 当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。否则新的进程等待。

2. 交互式系统

交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。

2.1 时间片轮转

将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。

时间片轮转算法的效率和时间片的大小有很大关系:

  • 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
  • 而如果时间片过长,那么实时性就不能得到保证。

总而言之,就是时间轮转,让每一个都有执行时间,时间片不易过大或过小。

2.2 优先级调度

为每个进程分配一个优先级,按优先级进行调度。

为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

总而言之,按优先级来,等待久了还会增加优先级,保证实时性。

2.3 多级反馈队列

一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法,那么需要交换 100 次。

多级队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不同,例如 1,2,4,8,..。进程在第一个队列没执行完,就会被移到下一个队列。这种方式下,之前的进程只需要交换 7 次。

每个队列优先权也不同,最上面的优先权最高。因此只有上一个队列没有进程在排队,才能调度当前队列上的进程。

总而言之,可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。

3. 实时系统

实时系统要求一个请求在一个确定时间内得到响应。

分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时。




  • ★★☆ 常见进程同步问题。

什么是临界区?

对临界资源进行访问的那段代码称为临界区。

为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。

什么时同步与互斥?

同步:多个进程因为合作产生的直接制约关系,使得进程有一定的先后执行关系。

互斥:多个进程在同一时刻只有一个进程能进入临界区。

1.生产者消费者模型

使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。

2.哲学家进餐模型

五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。

下面是一种错误的解法,如果所有哲学家同时拿起左手边的筷子,那么所有哲学家都在等待其它哲学家吃完并释放自己手中的筷子,导致死锁。

为了防止死锁的发生,可以设置两个条件:

必须同时拿起左右两根筷子;

只有在两个邻居都没有进餐的情况下才允许进餐。


  • ★★★ 进程通信方法的特点以及使用场景。

进程同步与进程通信很容易混淆,它们的区别在于:

进程同步:控制多个进程按一定顺序执行;

进程通信:进程间传输信息。

进程通信是一种手段,而进程同步是一种目的。也可以说,为了能够达到进程同步的目的,需要让进程进行通信,传输一些进程同步所需要的信息。

1.管道

只支持半双工通信(单向交替传输);

只能在父子进程或者兄弟进程中使用。

2.FIFO

也称为命名管道,去除了管道只能在父子进程中使用的限制。FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。

3.消息队列

相比于 FIFO,消息队列具有以下优点:

消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;

避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;

读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。

4.信号量

它是一个计数器,用于为多个进程提供对共享数据对象的访问。

5.共享存储

6.套接字

用于不同机器间的进程通信。


  • ★★★ 死锁必要条件、解决死锁策略,能写出和分析死锁的代码,能说明在数据库管理系统或者 Java 中如何解决死锁。

什么是死锁?死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

死锁产生的必要条件?(这个地方说的有点太书面了,不太好理解)互斥:每个资源要么已经分配给了一个进程,要么就是可用的。占有和等待:已经得到了某个资源的进程可以再请求新的资源。不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。

解决死锁的策略?

鸵鸟策略

把头埋在沙子里,假装根本没发生问题。因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。

死锁检测与死锁恢复

不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。

死锁预防

在程序运行之前预防发生死锁。

死锁避免

在程序运行时避免发生死锁。


  • ★★★ 虚拟内存的作用,分页系统实现虚拟内存原理。

虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。

为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。

从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。


  • ★★★ 页面置换算法的原理

在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

具体哪一种算法先不了解了,主要有最佳,最近最久,先进先出,第二次机会算法,时钟。


  • ★★★ 比较分页与分段的区别。
  • 对程序员的透明性:分页透明,但是分段需要程序员显式划分每个段。
  • 地址空间的维度:分页是一维地址空间,分段是二维的。
  • 大小是否可以改变:页的大小不可变,段的大小可以动态改变。
  • 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。

段页式存储:

  • 程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。

例子:

打个比方,比如说你去听课,带了一个纸质笔记本做笔记。笔记本有100张纸,课程有语文、数学、英语三门,对于这个笔记本的使用,为了便于以后复习方便,你可以有两种选择。


第一种是,你从本子的第一张纸开始用,并且事先在本子上做划分:第2张到第30张纸记语文笔记,第31到60张纸记数学笔记,第61到100张纸记英语笔记,最后在第一张纸做个列表,记录着三门笔记各自的范围。这就是分段管理,第一张纸叫段表。

第二种是,你从第二张纸开始做笔记,各种课的笔记是连在一起的:第2张纸是数学,第3张是语文,第4张英语……最后呢,你在第一张纸做了一个目录,记录着语文笔记在第3、7、14、15张纸……,数学笔记在第2、6、8、9、11……,英语笔记在第4、5、12……。这就是分页管理,第一张纸叫页表。

2.2 Linux


  • ★★☆ 文件系统的原理,特别是 inode 和 block。

组成

最主要的几个组成部分如下:

  • inode:一个文件占用一个 inode,记录文件的属性,同时记录此文件的内容所在的 block 编号;
  • block:记录文件的内容,文件太大时,会占用多个 block。

除此之外还包括:

  • superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
  • block bitmap:记录 block 是否被使用的位图。

block

在 Ext2 文件系统中所支持的 block 大小有 1K,2K 及 4K 三种,不同的大小限制了单个文件和文件系统的最大大小。

大小 1KB 2KB 4KB
最大单一文件 16GB 256GB 2TB
最大文件系统 2TB 8TB 16TB

一个 block 只能被一个文件所使用,未使用的部分直接浪费了。因此如果需要存储大量的小文件,那么最好选用比较小的 block。

inode

inode 具体包含以下信息:

  • 权限 (read/write/excute);
  • 拥有者与群组 (owner/group);
  • 容量;
  • 建立或状态改变的时间 (ctime);
  • 最近读取时间 (atime);
  • 最近修改时间 (mtime);
  • 定义文件特性的旗标 (flag),如 SetUID...;
  • 该文件真正内容的指向 (pointer)。

https://blog.csdn.net/qq_41901915/article/details/89458784

文件的各种属性见这个博客

inode 具有以下特点:

  • 每个 inode 大小均固定为 128 bytes (新的 ext4 与 xfs 可设定到 256 bytes);
  • 每个文件都仅会占用一个 inode。

inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用让 inode 记录的引用 block 块记录引用信息。


  • ★★★ 硬链接与软链接的区别。

什么是软链接?相当于快捷方式,只是一个链接,删除源文件这个快捷方式就不好使了。

什么是硬链接?相当于复制一份+同步更新,内容和大小完全和源文件一样,当修改源文件的内容时,硬链接的内容也会更改。

建立链接的语法:

软链接:ln -s 源文件 目标文件
硬链接:ln 源文件 目标文件
源文件:即你要对谁建立链接


  • ★★☆ 能够使用常用的命令,比如 cat 文件内容查看、find 搜索文件,以及 cut、sort 等管线命令。了解 grep 和 awk 的作用。

https://blog.csdn.net/qq_41901915/article/details/89551890


  • ★★★ 僵尸进程与孤儿进程的区别

什么是孤儿进程?一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被 init 进程(进程号为 1)所收养,并由 init 进程对它们完成状态收集工作。由于孤儿进程会被 init 进程收养,所以孤儿进程不会对系统造成危害。

什么是僵尸进程?子进程退出后留下的进程信息没有被收集,会导致占用的进程控制块PCB不被释放,形成僵尸进程。进程已经死去,但是进程资源没有被释放掉。

僵尸进程的解决:可以杀死父进程,这样僵尸会变成孤儿,从而被收养。


3. 网络

3.1 基础


  • ★★★ 各层协议的作用,以及 TCP/IP 协议的特点。
  • 应用层 :为特定应用程序提供数据传输服务,例如 HTTP、DNS 等协议。数据单位为报文。
  • 传输层 :为进程提供通用数据传输服务。由于应用层协议很多,定义通用的传输层协议就可以支持不断增多的应用层协议。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。
  • 网络层 :为主机提供数据传输服务。而传输层协议是为主机中的进程提供数据传输服务。网络层把传输层传递下来的报文段或者用户数据报封装成分组。
  • 数据链路层 :网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的主机提供数据传输服务。数据链路层把网络层传下来的分组封装成帧。
  • 物理层 :考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。

  • ★★☆ 以太网的特点,以及帧结构。


  • ★★☆ 集线器、交换机、路由器的作用,以及所属的网络层。

集线器:集线器工作在第一层(即物理层),它没有智能处理能力,对它来说,数据只是电流而已,当一个端口的电流传到集线器中时,它只是简单地将电流传送到其他端口,至于其他端口连接的计算机接收不接收这些数据,它就不管了。

交换机:交换机工作在第二层(即数据链路层),它要比集线器智能一些,对它来说,网络上的数据就是MAC地址的集合,它能分辨出帧中的源MAC地址和目的MAC地址,因此可以在任意两个端口间建立联系,但是交换机并不懂得IP地址,它只知道MAC地址。

路由器:路由器工作在第三层(即网络层),它比交换机还要“聪明”一些,它能理解数据中的IP地址,如果它接收到一个数据包,就检查其中的IP地址,如果目标地址是本地网络的就不理会,如果是其他网络的,就将数据包转发出本地网络。


  • ★★☆ IP 数据数据报常见字段的作用。

感觉这个地方没有背的必要,用的时候查一下就好了


  • ★★★ 理解三次握手以及四次挥手具体过程,三次握手的原因、四次挥手原因、TIME_WAIT 的作用。

三次握手是为了建立链接,四次挥手是为了断开链接。

确认 ACK :当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。

同步 SYN :在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。

终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。

三次握手的原因

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

四次挥手的原因

这个状态是为了让服务器端发送还未传送完毕的数据。

TIME_WAIT

客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:

确保最后一个确认报文能够到达。

等待一段时间是为了让所有旧的报文从网络中消失。



  • ★★☆ TCP 拥塞控制的作用,理解具体原理。

作用:防止过多的数据注入到网络当中,这样可以使网络中的路由器或链路不致过载。

慢开始:由于不知道现在网络状态是什么样的,所以一下子不可以那么大,要慢慢的变大。

拥塞避免:当达到门限的时候,就会执行拥塞避免,因为网络流量已经达到了一定的速度,再增长过快,很容易出现拥塞,所以要放慢速度。

快重传:等待重传的ACK时间可能很长,造成很多空闲时刻的浪费,所以规定客户端如果一连收到三个重复的ACK,那么不必等待重传计时器到期,尽早重传未被确认的报文段。

快恢复:由于发送方现在认为网络很可能没有发生阻塞,因此现在不执行慢启动算法,而是把cwnd值设置为慢启动门限减半后的值,然后开始执行拥塞避免算法,拥塞窗口cwnd值线性增大。


3.2 HTTP


  • ★★★ GET 与 POST 比较:作用、参数、安全性、幂等性、可缓存。

get把请求的数据放在url上,post把数据放在HTTP的包体内(requrest body)。

post比get更加安全。

get具有幂等性,post没有幂等性。

HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同

那么,post那么好为什么还用get?get效率高!


  • ★★☆ HTTP 状态码。

200 OK:表示从客户端发送给服务器的请求被正常处理并返回;

302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;

404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;

500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;


  • ★★★ Cookie 作用、安全性问题、和 Session 的比较。

Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,一般用于客户端,session一般用于服务器端。

Cookie 只能存储 ASCII 码字符串,而 Session 则可以存储任何类型的数据,因此在考虑数据复杂性时首选 Session;

Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;

对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。


  • ★★☆ 缓存 的Cache-Control 字段,特别是 Expires 和 max-age 的区别。

max-age 指令出现在请求报文,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。

max-age 指令出现在响应报文,表示缓存资源在缓存服务器中保存的时间。

Cache-Control: max-age=31536000Copy to clipboardErrorCopied

Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。

Expires: Wed, 04 Jul 2012 08:26:05 GMTCopy to clipboardErrorCopied
  • 在 HTTP/1.1 中,会优先处理 max-age 指令;

  • ★★★ 长连接与短连接原理以及使用场景,流水线。

短链接:建立一次TCP链接,进行一次http通信。耗费资源但是安全。

长连接:建立一次TCP链接,进行多次http通信。不太安全但是节省资源。

权衡安全性和资源耗费性自然就有了他们各自的应用场景。

流水线:它是在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。


  • ★★★ HTTP 存在的安全性问题,以及 HTTPs 的加密、认证和完整性保护作用。

HTTP 有以下安全性问题:

使用明文进行通信,内容可能会被窃听

不验证通信方的身份,通信方的身份有可能遭遇伪装

无法证明报文的完整性,报文有可能遭篡改

HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是说 HTTPS 使用了隧道进行通信。

通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。

3.3 Socket


  • ★★☆ 五种 IO 模型的特点以及比较。

一、I/O 模型

一个输入操作通常包括两个阶段:

  • 等待数据准备好
  • 从内核向进程复制数据

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待数据到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。

Unix 有五种 I/O 模型:

  • 阻塞式 I/O
  • 非阻塞式 I/O
  • I/O 复用(select 和 poll)
  • 信号驱动式 I/O(SIGIO)
  • 异步 I/O(AIO)

阻塞式 I/O

应用进程被阻塞,直到数据从内核缓冲区复制到应用进程缓冲区中才返回。

应该注意到,在阻塞的过程中,其它应用进程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率会比较高。

下图中,recvfrom() 用于接收 Socket 传来的数据,并复制到应用进程的缓冲区 buf 中。这里把 recvfrom() 当成系统调用。

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);Copy to clipboardErrorCopied

非阻塞式 I/O

应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。

由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。

I/O 复用

使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。

它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。

如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。

信号驱动 I/O

应用进程使用 sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。

相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。

异步 I/O

应用进程执行 aio_read 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。

异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。

五大 I/O 模型比较

  • 同步 I/O:将数据从内核缓冲区复制到应用进程缓冲区的阶段(第二阶段),应用进程会阻塞。
  • 异步 I/O:第二阶段应用进程不会阻塞。

同步 I/O 包括阻塞式 I/O、非阻塞式 I/O、I/O 复用和信号驱动 I/O ,它们的主要区别在第一个阶段。

非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。


  • ★★★ select、poll、epoll使用场景;

select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll。

1. select 应用场景

select 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。

select 可移植性更好,几乎被所有主流平台所支持。

2. poll 应用场景

poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。

3. epoll 应用场景

只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接

需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。

需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。


4. 数据库

4.1 SQL


  • ★★☆ 手写 SQL 语句,特别是连接查询与分组查询。

https://blog.csdn.net/qq_41901915/article/details/82758909


4.2 系统原理


  • ★★★ ACID 的作用以及实现原理。

原子性(Atomicity,或称不可分割性)一致性(Consistency)隔离性(Isolation)持久性(Durability)

 原子性:事务里面的操作单元不可切割,要么全部成功,要么全部失败 。

实现原理:实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的 sql 语句。基于undo log

一致性:事务执行前后,业务状态和其他业务状态保持一致.。

实现原理:事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障。

隔离性:一个事务执行的时候最好不要受到其他事务的影响 

实现原理:事务的四大隔离级别。

持久性:一旦事务提交或者回滚.这个状态都要持久化到数据库中 

实现原理:redo log 采用的是 WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到 Buffer Pool,保证了数据不会因 MySQL 宕机而丢失,从而满足了持久性要求。


  • ★★★ 四大隔离级别,以及不可重复读和幻影读的出现原因。

什么是脏读?

在一个事务中读取到另一个事务没有提交的数据(针对未提交数据)

什么是不可重复读?

在一个事务中,两次查询的结果不一致(针对的update操作)

什么是虚幻读?

在一个事务中,两次查询的结果不一致(针对的insert操作)

通过设置数据库的隔离级别来避免上面的问题(四大隔离级别)
read uncommitted    读未提交    上面的三个问题都会出现 
read committed      读已提交    可以避免脏读的发生 
repeatable read     可重复读    可以避免脏读和不可重复读的发生 
serializable        串行化     可以避免所有的问题


  • ★★☆ 封锁粒度

MySQL 中提供了两种封锁粒度:行级锁以及表级锁。

应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。

但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。

在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。


  • ★★★ 乐观锁与悲观锁。

什么是悲观锁?(适用于多写操作的系统)总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。

什么是乐观锁?(适用于少写操作的系统)总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。

什么是CAS算法?compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。





  • ★★☆ 范式理论。

关系数据库有六种范式:第一范式1NF)、第二范式(2NF)、第三范式(3NF)、第四范式(4NF)、第五范式(5NF)和第六范式(6NF)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。

第一范式:在任何一个关系数据库中,第一范式1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。实体中的某个属性不能有多个值或者不能有重复的属性。每一行只包含一个实例的信息。

第二范式:满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。

第三范式:属性不依赖于其它非主属性,紧紧依赖于主属性。


  • ★★★ SQL 与 NoSQL 的比较。

SQL (Structured Query Language) 数据库,指关系型数据库。主要代表:SQL Server,Oracle,MySQL,PostgreSQL。

NoSQL(Not Only SQL)泛指非关系型数据库。主要代表:MongoDB,Redis,CouchDB。

NoSQL的优点

1.简单的扩展:典型例子是Cassandra,由于其架构是类似于经典的P2P,所以能通过轻松地添加新的节点来扩展这个集群;

2.快速的读写:主要例子有Redis,由于其逻辑简单,而且纯内存操作,使得其性能非常出色,单节点每秒可以处理超过10万次读写操作;

3.低廉的成本:这是大多数分布式数据库共有的特点,因为主要都是开源软件,没有昂贵的License成本;

 区别:

a 存储方式

SQL数据存在特定结构的表中;

而NoSQL则更加灵活和可扩展,存储方式可以是JSON文档、哈希表或者其他方式。

b 表/集合数据的关系

SQL中,必须定义好表和字段结构后才能添加数据,例如定义表的主键(primary key),索引(index),触发器(trigger),存储过程(stored procedure)等。表结构可以在被定义之后更新,但是如果有比较大的结构变更的话就会变得比较复杂。

在NoSQL中,数据可以在任何时候任何地方添加,不需要先定义表。

c 外部数据存储

SQL中如果需要增加外部关联数据的话,规范化做法是在原表中增加一个外键,关联外部数据表。

NoSQL中除了这种规范化的外部数据表做法以外,我们还能用如下的非规范化方式把外部数据直接放到原数据集中,以提高查询效率。缺点也比较明显,更新审核人数据的时候将会比较麻烦。

d SQL中的JOIN查询

SQL中可以使用JOIN表链接方式将多个关系数据表中的数据用一条简单的查询语句查询出来。

NoSQL未提供对多个数据集中的数据做查询。

e 数据耦合性

SQL中不允许删除已经被使用的外部数据,例如审核人表中的"熊三"已经被分配给了借阅人熊大,那么在审核人表中将不允许删除熊三这条数据,以保证数据完整性。

而NoSQL中则没有这种强耦合的概念,可以随时删除任何数据。


4.3 MySQL


  • ★★★ B+ Tree 原理,与其它查找树的比较。

与B树,红黑树作比较,这个地方比较难以理解,网上的博客说的也比较混乱,暂略。


  • ★★★ MySQL 索引以及优化。

  • ★★★ 查询优化。

  • ★★★ InnoDB 与 MyISAM 比较。

是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。

事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。

并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。

外键:InnoDB 支持外键。

备份:InnoDB 支持在线热备份。

崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。

其它特性:MyISAM 支持压缩表和空间数据索引。


  • ★★☆ 水平切分与垂直切分。

水平切分

水平切分又称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。

当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。

垂直切分

垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。

在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。


  • ★★☆ 主从复制原理、作用、实现。

这主要发生在集群当中,一个主服务器,多个从服务器,从服务器有着优先级,如果从服务器失效,直接通知主服务器去除掉该slave,如果主服务器失效,那么就按照优先级选择一个从服务器作为主服务器。

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

  • binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
  • I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
  • SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。

读写分离

主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。

任务分离

主从服务器任务分离,比如从服务器分担计算工作。


4.4 Redis


  • ★★☆ 跳跃表原理分析。

是有序集合的底层实现之一。

跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。

在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。

与红黑树等平衡树相比,跳跃表具有以下优点:

  • 插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;
  • 更容易实现;
  • 支持无锁操作。

  • ★★★ Redis使用场景。

1、缓存

缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。

2、排行榜

很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。

3、计数器

什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。

4、分布式会话

集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。

5、分布式锁

在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。


加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!

加油!


  • ★★★ Redis与 Memchached 的比较。

1.性能:数据量小的时候redis好,数据量大的时候Memcached好。

2.所支持的数据类型:与Memcached仅支持简单的key-value结构的数据记录不同,Redis支持的数据类型要丰富得多。最为常用的数据类型主要由五种:String、Hash、List、Set和Sorted SetRedis内部使用一个redisObject对象来表示所有的key和value

3.数据备份恢复:memcached挂掉后,数据不可恢复;redis数据丢失后可以通过aof恢复。

4.数据存储:Redis和Memcached都是将数据存放在内存中,都是内存数据库。不过memcached还可用于缓存其他东西,例如图片、视频等等。memcached把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小;redis有部份存在硬盘上,这样能保证数据的持久性,支持数据的持久化(RDB、AOF),而Memcached不支持持久化。


  • ★★☆ RDB 和 AOF 持久化机制。

什么是RDB?

以一种快照的形式,将某个时间点的所有数据都存放到硬盘上。保存起来比较慢,但恢复的比较快。

什么AOF?

以一种日志的形式记录每一次的写命令,对文件的写入不是直接写入,而是先写入到日志当中,然后由操作系统决定什么时候写入到硬盘。记录的比较快,但恢复比较慢。这种方式需要设置同步选项。

选项 同步频率
always 每个写命令都同步
everysec 每秒同步一次
no 让操作系统来决定何时同步

always 选项会严重减低服务器的性能;

everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;

no 选项并不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量。


  • ★★☆ 事件驱动模型。

Redis 服务器是一个事件驱动程序。

文件事件

服务器通过套接字与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象。

Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。

时间事件

服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。

时间事件又分为:

  • 定时事件:是让一段程序在指定的时间之内执行一次;
  • 周期性事件:是让一段程序每隔指定时间就执行一次。

Redis 将所有时间事件都放在一个无序链表中,通过遍历整个链表查找出已到达的时间事件,并调用相应的事件处理器。

从事件处理的角度来看,服务器运行流程如下:



  • ★★★ 集群与分布式。

集群是个物理形态,分布式是个工作方式。

分布式:一个业务分拆多个子业务,部署在不同的服务器上

集群:同一个业务,部署在多个服务器上

分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。

好的设计应该是分布式和集群的结合,先分布式再集群,具体实现就是业务拆分成很多子业务,然后针对每个子业务进行集群部署,这样每个子业务如果出了问题,整个系统完全不会受影响。


  • ★★☆ 事务原理。

一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。

事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务器之间的网络通信次数从而提升性能。

Redis 最简单的事务实现方式是使用 MULTI 和 EXEC 命令将事务操作包围起来。

事务具有ACID四个特性


5. 面向对象

5.1 思想


  • ★★★ 面向对象三大特性

封装,继承,多态。


  • ★☆☆ 设计原则

单一职责原则:专注降低类的复杂度,实现类要职责单一;

开放关闭原则:所有面向对象原则的核心,设计要对扩展开发,对修改关闭;

里式替换原则:实现开放关闭原则的重要方式之一,设计不要破坏继承关系;

依赖倒置原则:系统抽象化的具体实现,要求面向接口编程,是面向对象设计的主要实现机制之一;

接口隔离原则:要求接口的方法尽量少,接口尽量细化;

迪米特法则:降低系统的耦合度,使一个模块的修改尽量少的影响其他模块,扩展会相对容易;


5.2 设计模式

  • ★★★ 手写单例模式,特别是双重检验锁以及静态内部类。
  • ★★★ 手写工厂模式。
  • ★★★ 理解 MVC,结合 SpringMVC 回答。
  • ★★★ 理解代理模式,结合 Spring 中的 AOP 回答。
  • ★★★ 分析 JDK 中常用的设计模式,例如装饰者模式、适配器模式、迭代器模式等。
发布了415 篇原创文章 · 获赞 434 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/qq_41901915/article/details/103672370