面试复习
网络相关
Http和Tcp的关系?
Tcp在传输层,Http在应用层,Http是建立在TCP连接的基础上的,TCP是单纯的建立连接,而Http是实际应用收发数据的.
网络分为哪几层?
物理层,数据链路层,网络层 传输层,(会话层,表示层)应用层
Http在哪层?
Http在应用层.
为什么分层?
为了降低网络设计的复杂性,绝大多数的网络都组织成一个层次栈,或者分级栈,每一层建立在其下一层的基础之上.层的个数,每一层的名字,每一层的内容以及每一层的功能各个网络不尽相同.
每一层的目的就是向上以曾提供特定的服务,而把如何实现这些服务的细节对上一层加以屏蔽.从某种意义上来叔,每一层就是一种虚拟机,向上一层一共特定的服务.
封装,类似面向对象设计
get,post请求的区别
GET参数通过URL传递,POST放在Request body中。
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行URL编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET和POST还有一个重大区别,简单的说:
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
幂等性
HTTP 幂等方法,是指无论调用多少次都不会有不同结果的 HTTP 方法。不管你调用一次,还是调用一百次,一千次,结果都是相同的。
幂等性指的是作用于结果而非资源本身。怎么理解呢?例如,这个 HTTP GET 方法可能会每次得到不同的返回内容,但并不影响资源。
GET是幂等的,POST是非幂等的。
如何设计符合幂等性的高质量 RESTful API
HTTP GET vs HTTP POST
也许,你会想起一个面试题。HTTP 请求的 GET 与 POST 方式有什么区别? 你可能会回答到:GET 方式通过 URL 提交数据,数据在 URL 中可以看到;POST 方式,数据放置在 HTML HEADER 内提交。但是,我们现在从 RESTful 的资源角度来看待问题,HTTP GET 方法是幂等的,所以它适合作为查询操作,HTTP POST 方法是非幂等的,所以用来表示新增操作。
但是,也有例外,我们有的时候可能需要把查询方法改造成 HTTP POST 方法。比如,超长(1k)的 GET URL 使用 POST 方法来替代,因为 GET 受到 URL 长度的限制。虽然,它不符合幂等性,但是它是一种折中的方案。
TCP和UDP
TCP面向连接,UDP无连接
TCP面向字节流(文件传输),UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对IP电话,实时视频会议等)
TCP首部开销20字节,UDP首部开销8个字节。
TCP提供可靠的服务,通过TCP连接传输的数据,无差错,不丢失,不重复,按序到达。UDP尽最大努力交付,既不保证可靠交付。
每一条TCP连接只能是点到点的;UDP支持一对一、一对多、多对一、多对多的交互通信。
TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
TCP如何保证数据的可靠传输
应用数据被分割成TCP认为最适合发送的数据块
TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
校验和:TCP将保持它首部和数据的检验和。这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果受到段的检验和有差错,TCP将丢弃这个报文段和不确认受到此报文段。
TCP的接收端会丢弃重复的数据。
流量控制:TCP连接的每一方都有固定的大小的缓冲控件,TCP接收端只允许发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的数据,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。(TCP利用滑动窗口实现流量控制)
拥塞控制:当网络拥塞时,减少数据的发送。
ARQ协议:实现可靠传输,基本原理是每发完一个分组就停止发送,等待对方确认后再发下一个分组。
超时重传:当TCP发出一个段后,它启动一个定时器,等待目的端确认受到这个报文段。如果不能及时收到确认,将重发这个报文段。
TCP三次握手建立连接,四次挥手断开连接.
为什么需要三次握手
三次握手的目的是建立可靠的通信信道,简单来说就是数据的发送和接收,而三次握手主要的目的就是双方确认自己与对方的发送与接收是正常的。
第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
所以三次握手就能确认双发收发功能都正常,缺一不可。
为什么需要四次挥手
任何一方都可以在数据传输结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。
操作系统相关
进程和线程有什么区别?
进程是执行的程序,但不只是程序代码,还包括当前活动,如程序计数器的值和处理器寄存器的内容等.
进程
-
文本段
- 程序代码
-
进程堆栈 stack
-
临时数据
函数参数
返回地址
局部变量
-
-
数据段
- 全局变量
-
堆 heap
- 在进程运行时动态分配的内存
线程
每个线程是CPU使用的几个基本单元,它拥有自己的
线程ID
程序计数器
寄存器
堆栈
一个进程可以有多个线程,但至少有一个线程;而一个线程只能在一个进程的地址空间内活动。
资源分配给进程,同一个进程的所有线程共享该进程所有资源。
CPU分配给线程,即真正在处理器运行的是线程。
线程在执行过程中需要协作同步,不同进程的线程间要利用消息通信的办法实现同步。
哪些资源进程共享,线程共享?
它与统一进程的其他线程共享
代码段
数据段
其它系统操作资源
线程死掉和进程死掉有什么关系?
如果进程被kill其包含的线程也会被kill
如果线程被kill其所属的进程做出相应处理,如自动创建,启动线程,抛出异常等。
进程之间能共享内存吗? 具体的实现方式?
进程间的通信方式
-
消息传递
通过在协作进程间交换信息来实现通信。
消息传递对于交换次数较少数量的数据比较有用,无需避免冲突,对于分布式系统,消息传递也比共享内存更易实现。
-
共享内存
共享内存模型会建立起一块供协作进程共享的内存区域,进程通过向此共享区域读出或写入数据来交换信息。
共享内存快于消息传递,仅在建立共享区域内存时需要系统调用,一旦建立共享区域,所有访问都可作为常规的内存访问。
有高速缓存一致性问题
管道通信
进程调度
-
先到先服务调度FCFS
非抢占,平均等待时间过长
-
最短作业优先调度 SJF
预测下一个CPU执行的长度
可以抢占(最短剩余时间优先调度)或非抢占。
-
优先级调度
最短作业优先调度的一般形式
无穷阻塞,饥饿问题。用老化解决
-
轮转调度 RR
抢占调度,时间片远大于上下文切换时间,保证性能
分时系统,以时间片为单位,循环调度整个就绪队列。
-
多级队列调度
将就绪队列分成多个单独队列,根据进程属性如
内存大小
进程优先级
进程类型
每个队列有自己的调度算法。队列之间采用固定优先级调度。
-
多级反馈队列
允许进程在队列之间迁移,根据不同CPU特点来区分进程。
如果进程过多的使用CPU时间那么他会被移到更低的优先级队列。
如果低优先级队列中等待过长的进程会被移动到更高的优先级队列。
线程调度
用户级
-
内核级
内核级线程才是操作系统所调度的,用户级线程是由线程库来管理的,而内核并不知道他们。
竞争范围
-
进程竞争范围PCS
对于实现多对一 多对多模型的系统,线程库会调度用户级线程,以便在可用的LWP上运行。竞争发生在同一进程的线程之间。
通常采用优先级调度,用户级线程的优先级由程序员设置。
-
系统竞争范围SCS
- 为了决定哪个内核级线程调度到一个处理器上,内核采用系统竞争范围。采用SCS调度来竞争CPU,发生在系统内的所有线程之间。采用一对一模型。
Pthreads调度
-
堆和栈的区别?
栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。
堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
临界区问题
互斥锁,获得锁,释放锁,忙等待。
信号量,wait--和signal++ 计数信号量
死锁和饥饿
进程死锁的四个条件
-
互斥
- 至少有一个资源处于非共享模式,一次只有一个进程可以使用.
-
占有并等待
- 一个进程至少占有一个资源,并等待另一个资源,该资源被其余进程所占有.
-
非抢占
- 资源不能被抢占.
循环等待
并发和并行的区别
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
算法相关
排序算法
选择排序
找到最小放在最前面.
最坏情况复杂度:
平均复杂度:
稳定的
插入排序
从左到右开始,像理手牌一样将牌插入相应顺序的位置.
最坏情况复杂度:
平均复杂度:
稳定的
希尔排序
最坏情况复杂度:
平均复杂度:
不稳定的
快速排序
最坏情况复杂度:
期望时间复杂度:
不稳定的
归并排序
最坏情况复杂度:
平均复杂度:
稳定的
堆排序
堆的构造: 自底向上 从第一个非叶子结点开始,维护大根堆或小根堆的性质.
下沉排序: 自顶向下,将根节点提出放入序列,将最后一个节点位置放至根节点,并再次维护堆的性质.
最坏情况复杂度:
平均复杂度:
不稳定的
计数排序
最坏情况复杂度:
平均复杂度:
稳定的
桶排序
分割成多个桶,桶内进行排序算法.
最坏情况复杂度:
平均复杂度:
稳定的
基数排序
从最后一位开始排序,依次到第一位
最坏情况复杂度:
平均复杂度:
稳定的
数据库相关
事务的四个特点ACID
原子性
一致性
隔离性
持久性
Java相关
HashMap
HashCode找到数组下标
数组+链表+红黑树
装箱拆箱
装箱就是 自动将基本数据类型转换为包装器类型;
拆箱就是 自动将包装器类型转换为基本数据类型。
装箱过程是通过调用包装器的valueOf方法实现的,
而拆箱过程是通过调用包装器的 xxxValue方法实现的(xxx代表对应的基本数据类型)。
Java中的wait和notify方法
wait是对象通知持有自己锁的线程释放我的锁
notify()/notifyAll()就是对象通知刚刚被自己晾在一边的线程又可以来竞争我的锁了。
参考资源
https://www.nowcoder.com/discuss/402229?type=2 面经
https://www.nowcoder.com/discuss/400315?type=post&order=create&pos=&page=1 面经2
https://www.jianshu.com/p/9d46a730284e 幂等性
https://www.cnblogs.com/baizhanshi/p/8482612.html TCP HTTP
https://www.cnblogs.com/gmpy/p/10265284.html 进程与线程调度
https://blog.csdn.net/jianghao233/article/details/82777789
https://www.cnblogs.com/dolphin0520/p/3780005.html 装箱 拆箱
https://www.cnblogs.com/shen-qian/p/11265631.html wait notify