最近面试,复习并总结了一波基础知识。( ̄▽ ̄)”
首先,肥肠感谢lightina的博客,从中抄到了很多东西,省去了翻书整理的时间学到了很多东西,收获颇丰。
其实都学过,然而……忘的差不多了(⊙﹏⊙)
七层模型
七层结构
层次名字 | 数据格式(PDU) | 设备 | 典型协议 |
---|---|---|---|
应用层 | 数据 | - | - |
表示层 | 数据 | - | MIME,SSL,TLS,XDR |
会话层 | 数据 | - | Sockets (session establishment in TCP / RTP / PPTP) |
传输层 | 数据组成的数据段(Segment) | - | TCP,UDP |
网络层 | 分割和重新组合的数据包(Packet) | 网关,路由器 | IP,ICMP,RIP,RIP,IGMP,OSPF |
数据链路层(MAC,LLC) | 比特信息封装成的数据帧(Frame) | 网桥,交换机 | ARP,RARP,PPP,CSMA/CD |
物理层 | 传输比特流(bit) | 光纤,同轴电缆,双绞线,网卡等 | - |
分层的优点
- 各层之间独立,不用知道下层的实现
- 灵活性好,某一层发生变化不影响其他的层
- 便于实现维护以及促进标准化
TCP/UDP
特点 | TCP | UDP |
---|---|---|
是否面向连接 | 面向连接 | 面向非连接 |
可靠性 | 可靠 | 不可靠 |
相关协议 | FTP,TELNET,SMTP,POP3,HTTP | DNS,SNMP(简单网络管理),TFTP |
备注 | 流控制以及错误恢复功能 | 头包含很少的字节,比 TCP 负载消耗少 |
HTTP
HTTP版本:0.9
,1.0
,1.1
HTTP 1.1 的相关方法
- GET
- HEAD
- POST
- OPTIONS
- PUT
- DELETE
- TRACE
- CONN
- ETC
使用MIME协议决定传输内容
三次握手&四次挥手
第一次握手
客户端向服务端发送连接请求报文段。该报文段的头部中SYN=1,ACK=0,seq=x。请求发送后,客户端便进入SYN-SENT状态。SYN=1的报文段不能有数据部分,但要消耗掉一个序号。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答:SYN=1,ACK=1,seq=y,ack=x+1。
该应答发送完成后便进入SYN-RCVD状态。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示:服务端发来的连接同意应答已经成功收到。 该报文段的头部为:ACK=1,seq=x+1,ack=y+1。 客户端发完这个报文段后便进入ESTABLISHED状态,服务端收到这个应答后也进入ESTABLISHED状态,此时连接的建立完成!
为什么连接建立需要三次握手
防止失效的连接请求报文段被服务端接收,从而产生错误。
此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。
第一次挥手
若A认为数据发送完成,则它需要向B发送连接释放请求。该请求只有报文头,头中携带的主要参数为:
FIN=1,seq=u。此时,A将进入FIN-WAIT-1状态。
第二次挥手
B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放。此时B进入CLOSE-WAIT状态,并向A发送连接释放的应答,其报文头包含: ACK=1,seq=v,ack=u+1。
A收到该应答,进入FIN-WAIT-2状态,等待B发送连接释放请求。
第二次挥手完成后,A到B方向的连接已经释放,B不会再接收数据,A也不会再发送数据。但B到A方向的连接仍然存在,B可以继续向A发送数据。
第三次挥手
当B向A发完所有数据后,向A发送连接释放请求,请求头:FIN=1,ACK=1,seq=w,ack=u+1。B便进入LAST-ACK状态。
第四次挥手
A收到释放请求后,向B发送确认应答,此时A进入TIME-WAIT状态。该状态会持续2MSL时间,若该时间段内没有B的重发请求的话,就进入CLOSED状态,撤销TCB。当B收到确认应答后,也便进入CLOSED状态,撤销TCB。
为什么等待2MSL
为了保证B能收到A的确认应答。 若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭
JVM内存模型
所有线程共享的:
- 方法区
- 存储已经被加载的类,常量,静态变量,即时编译后的代码等
- 虚拟机规范将方法区描述为堆的逻辑部分
- 别名
Non-Heap
- 堆
- 可以简单的分为
新生代
和年老代
- 细致的可以分为
Eden
,From Survivor
,To Survivor
等空间 - 内存中最大的一块
- 虚拟机启动的时候创建
- 所有Java对象都要在堆上进行分配(虚拟机规范中时这样的,然而并不绝对)
- 可以简单的分为
线程隔离的:
- 虚拟机栈
- 每次执行方法都会创建一个栈帧
- 本地方法栈
- 为VM使用到的Native方法服务
- 具体的VM可自由实现
- 有的虚拟机(eg:Sun HotSpot 虚拟机)将本地方法栈以及虚拟机栈合二为一
- 程序计数器
- 执行Java方法时,记录的时正在执行的虚拟机的字节码的地址
- 执行Native方法时,计数器的值为空(Undefined)
- 唯一一个没有规定OutOfMemoryError情况的区域
类加载过程
- 加载(Loading):查找和导入Class文件
- 连接:把类的而精致数据合并到JRE中
- 验证(Verification):检查载入Class文件数据的正确性
- 准备(Preparation):给类的静态变量分配存储空间
- 解析(Resolution):将符号引用转成直接引用
- 初始化(initialization):对类的静态变量,静态代码块执行初始化操作
- 使用(Using)
- 卸载(UnLoading)
双亲委派机制
一个ClassLoader查找资源时,先看看缓存是否有,有就从缓存中获取,否则委托给父加载器。然后递归,父加载器继续看缓存,直到Bootstrap ClassLoader,如果Bootstrap ClassLoader找到了,直接返回,如果没有找到,则一级一级返回,最后到达自身去查找这些对象
GC机制
- 引用计数法
- GC无法解决循环引用的问题
- 可达性分析
- GC roots
- 如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用
AOP
运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
应用:
- 读取缓存
- 日志持久化
volatile
解决可见性 多线程时 每个线程都有本地内存 保存着共享变量的副本
修改是对自己副本的修改且不会立刻刷新到主存去
禁止指令重拍序(单例模式双重检验后还需加volatile)
- 对volatile变量的写会立即刷新到主存
- 对volatile变量的读会读主存中的新值
竞争条件
- 计算机运行过程中,并发、无序、大量的进程在使用有限、独占、不可抢占的资源,由于进程无限,资源有限,产生矛盾,这种矛盾称为竞争
- 由于两个或者多个进程竞争使用不能被同时访问的资源,使得这些进程有可能因为时间上推进的先后原因而出现问题,这叫做竞争条件
竞争条件分为两类
- Mutex(互斥):两个或多个进程彼此之间没有内在的制约关系,但是由于要抢占使用某个临界资源(不能被多个进程同时使用的资源,如打印机,变量)而产生制约关系
- Synchronization(同步):两个或多个进程彼此之间存在内在的制约关系(前一个进程执行完,其他的进程才能执行),如严格轮转法
解决互斥方法
- Busy Waiting(忙等待)
- Sleep and Wakeup(睡眠与唤醒)
死锁
如果一个进程的集合中的每个进程都在等待只能由该进程集合中的其他进程才能够引发的时间,那么,这个进程的集合就是死锁的。
死锁条件
- 互斥(已分配/可用)
- 占有等待(持有资源后能够请求新的资源)
- 不可抢占
- 环路等待