操作系统

进程、线程、协程

一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。

Linux进程状态
进程通信
线程通信

1,锁机制(互斥锁提供了以排他方式防止数据结构被并发修改的方法,条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。 wait/notify 等待、Volatile 内存共享,CountDownLatch 并发工具);信号量机制(Semaphore);信号机制(Signal)。

2,消息队列(rabbitMQ):当不需要立即获得结果,异步处理:写入消息队列后立即返回客户端,无需等待;限流削峰:请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓冲, 极大地减少了业务处理系统的压力;

点对点模式:点对点的Queue,即Producer发送消息到指定的Queue,接收方从Queue收取消息。

一对多的Topic,即Producer发送消息到指定的Topic,任意多个在线的接收方均可从Topic获得一份完整的消息副本。当Producer想要发送消息的时候,它将消息发送给指定的Exchange,由Exchange将消息根据各种规则投递到一个或多个Queue()路由。送消息时,使用rabbitTemplate.convertAndSend(exchange, routingKey, message)可以指定Exchange、Routing Key以及消息本身。接收消息时,需要在消息处理的类上标注@RabbitListener指明要监听的queue,通过多个@RabbitHandler标注的方法接收不同类型的消息。

内存分段、分页

逻辑地址(完整、连续、进程隔离、更大内存);物理地址(非连续);地址转换

内存调度
磁盘调度
进程调度
进程切换
用户态、内核态

系统调用将 Linux 整个体系分为用户态和内核态;内核态:控制计算机的硬件资源、稳定安全;用户态:提供应用程序运行的空间、系统调用(os接口)、库函数对系统调用进行封装;给不同的操作给与不同的 “权限”、切换方式(系统调用、异常、外设中断)

调度

(饥饿、长短作业公平性、优先级)先来先服务、短作业优先、时间片轮转、多级队列(新进程优先级高、优先级高时间片越短、抢占式、级别降低)。

Linux调度

内核线程、调度基于线程,nice值越低优先级越高

死锁

前提:互斥资源、请求新资源、不可抢占、等待关系闭环。

死锁检测:单资源单向有向图环检测(以每个节点为起点,深度优先、重复)。

死锁恢复:抢占恢复(用完归还)、杀死进程(选择副作用小的进程)。

死锁避免:安全前提(存在非死锁序列)下分配资源(银行家算法)。

死锁预防:非独占(假脱机打印)、非占有等待(一次请求全部资源)、破坏不可抢占(请求失败释放占有资源)。破坏等待(资源编号、请求资源序号升序、无环产生)

尾递归

传统递归在递归返回后好需要继续运算,保留栈帧;空间O(N);尾递归在递归返回后无后续运算,当前递归结果已被收集(二叉查找树的左右子节点为参数),无需保留栈帧,空间O(1)

CAS

乐观锁;根据地址v取值A=get(v)->B=f(A)->A==get(v)->成立则将B写入v,失败则不断重复至成功;重复读取get(v),单变量原子性(封装),ABA问题(版本号比较)

阻塞非阻塞与同步异步

https://www.cnblogs.com/loveer/p/11479249.html

IO分两阶段1.数据准备阶段,2.内核空间复制数据到用户进程缓冲区(用户空间)阶段

I/O多路复用

通过一种机制,可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作,没有就绪事件时,就会阻塞交出cpu。多路是指多个链接,复用指的是复用同一线程。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。

https://developer.aliyun.com/article/763247

https://juejin.cn/post/6931543528971436046

NIO

https://tech.meituan.com/2016/11/04/nio.html

https://xie.infoq.cn/article/fb524c4992beea6bb4487af87

https://www.cnblogs.com/loveer/p/11479887.html

1,是一种同步非阻塞的 I/O 模型,在等待就绪阶段都是非阻塞的,真正的 I/O 操作是同步阻塞。是 I/O 多路复用的基础,成为解决高并发与大量连接、I/O 处理问题的有效方式。

2,服务器端同步阻塞 I/O 处理:socket.accept()、socket.read()、socket.write() 三个主要函数都是同步阻塞的,当一个连接在处理 I/O 的时候,系统是阻塞的,所以使用多线程时,就可以让 CPU 去处理更多的事情。低并发下结合线程池使得创建和回收成本相对较低,并且编程模型简单。创建和销毁都是重量级的系统函数,线程本身占用较大内存,线程的切换成本是很高的,无法应对百万级连接。

3,所有的系统 I/O 都分为两个阶段:等待就绪和操作。举例来说,读函数,分为等待系统可读和真正的读;同理,写函数分为等待网卡可以写和真正的写。NIO 里用户最关心” 我可以读了”。NIO的读写函数可以立刻返回而不是柱塞,如果一个连接不能读写(socket.read()返回0或者socket.write()返回0),我们可以把这件事记下来,将用于传输的通道全部注册到选择器上,选择器监控通道,当某一通道就绪后连接继续进行读写,没有必要开启多线程。没有线程切换,只是拼命的读、写、选择事件。

77752ed5

4,Java NIO 实际读写时的核心在于:通道(Channel)和缓冲区(Buffer),选择器。通道表示打开到 IO 设备(文件流、套接字)的连接,对原 I/O 包中的流的模拟,负责传输;缓冲区用于容纳数据,负责存储,Channel的读写必须通过buffer对象,然后操作缓冲区,对数据进行处理。缓存区是双向的,既可以往缓冲区写入数据,也可以从缓冲区读取数据:缓冲区<->然后缓冲区通过通道进行传输<->从缓冲区取数据。选择器:把Channel通道注册到Selector中,通过Selecotr监听Channel中的事件状态,这样就不需要阻塞等待客户端的连接,从主动等待客户端的连接,变成了通过事件驱动,通过事件驱动实现单线程管理多个Channel的目的。

0ece5d16ec1345a5b4dc2149cb5a8b40_tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0

缓冲区根据数据类型的不同,可以进行划分ByteBuffer、CharBuffer等。根据工作方式分:直接缓冲区(磁盘->内核地址空间中->用户地址空间中->读取到应用程序)与非直接缓冲区(将缓冲区建立在物理内存之中,读写数据直接通过物理内存进行),

上下文切换
进程内存布局