文章目录
- 一些背景知识
- 操作系统(OS)(计算机的大管家)
- 操作系统的基本概念:
- 市面上常见的操作操作系统:
- 关于前端与后端的介绍:(针对服务的体系架构)
- 计算机是如何工作的?(计算机内部具体的工作结构):
- 进程:
- 进程的概念:
- 进程相关的信息:
- 关于PCB的一些关键信息:
- 什么是进程调度? :
- 线程:
- 线程概念与一些问题
- 创建线程—代码实现
一些背景知识
操作系统(OS)(计算机的大管家)
操作系统的基本概念:
操作系统是建立在计算机硬件系统上的第一层系统软件,是对计算机硬件功能的抽象体现。
-
操作系统可以管理计算机硬件系统中的资源:如处理器资源,存储器资源, 文件资源,I/O设备资源。
操作系统是通过硬件设备上的驱动程序来间接管理硬件设备,而这些硬件设备的驱动程序是由 硬件设备厂商提供的.
-
操作系统也作为用户与计算机硬件系统资源的接口,比如我们常用的命令行方式(这是指由OS提供了一组联机命令(语言), 用户可通过键盘输入有关命令,来直接操纵计算机系统)。
-
操作系统为各个应用程序的运行提供了一个稳定的环境,即使其中一个应用程序崩溃,也不会干扰到其他应用程序的运行。
市面上常见的操作操作系统:
当前市面上常见的操作系统:
对于电脑端的,有著名的有windows系统(是微软公司开发),还有linux系统
我们作为后端开发程序员,主要与linux系统打交道,
还有苹果电脑上的(Mac OS系统)
对于手机端的有:android 安卓系统与 苹果手机上的IOS系统
关于前端与后端的介绍:(针对服务的体系架构)
客户端与服务器架构:
客户端是面向用户的,用户通过客户端发送请求,而服务器端是提供服务的,针对客户端发出的请求作出相应的回应。
常见的客户端有:
电脑与手机上的app软件。
电脑上的web端(浏览器)与手机上的web端(浏览器)。
服务器端:
服务器端分为服务器软件与服务器硬件设备,服务器软件安装在服务器硬件设备之上,
客户端与服务器端可能在一台硬件设备上,也可能在不同的硬件设备上,
客户端与服务器端的概念是相对的:比如我们的手机当我们选择一个功能时,我们的手机此时即是客户端,我们的手机可以根据我们的选项而提供对应的服务,则我们的手机又是服务器端了。
如果我们在手机上看b站视频,我们手机上的软件即客户端,而提供视频等资源的b站公司的服务器则是服务器端,此时客户端与服务器端则在不同的硬件设备上。
客户端与服务器端如果不处于同一台硬件设备上,他们之间的数据是通过网络来传输的,具体的实现则涉及计算机网络的知识,这里不作扩展。
后端即是服务器端程序的开发,前端是呈现给用户的页面展示程序开发,
以搜狗举例:
我们进入搜狗的网页:
展现给我们的即是前端页面,我们点击网页上的某个选项或者搜索什么,即向服务器端请求了服务,展现出了结果即是服务器端对客户端的回应。
计算机是如何工作的?(计算机内部具体的工作结构):
冯诺依曼体系结构:
存储设备
存储设备中实际上体系结构并不只是内存与硬盘两级,中间存在一些缓冲层级,这里只介绍内存与硬盘
内存与外存/硬盘的区别:
- 内存的访问速度快,硬盘的访问速度慢。(越靠近cpu的存储设备访问速度越快)
- 掉电后内存中的数据消失,而硬盘中的数据不会消失(最重要的特性!)
- 内存的容量小,硬盘的容量大
- 内存的成本高,硬盘的成本低
cpu
进程:
在介绍线程之前,需要先介绍进程
进程的概念:
进程可以说是一段分配了系统资源(如cpu, 内存,磁盘等资源)的程序段(含数据),
因为程序只有在被分配了系统资源后才可以被执行。
我们的应用程序在电脑上运行时,即创建了诸多进程来进行执行。
可以在任务管理器中查看当前电脑中的运行的进程:
注:一个应用程序在运行时可能不只创建一个进程,而是有多个进程
例如:对于此应用程序,系统为它的运行创建了11个进程。
进程相关的信息:
操作系统对进程的管理:
在计算机中有如此多的进程,需要对他们进行有效的管理,例如:学校老师对一个班级的学生进行管理时,管理的是每个学生的(学号,姓名,性别,专业,班级,年级)等信息,同样地,操作系统在管理进程时,通过使用一个结构体或者对象来描述一个进程,然后通过某种数据结构来集中管理这些进程(如:数组,链表,哈希等)进行相应的增删改查等操作。
比如Linux系统中是通过链表这样的格式来将所有的PCB组织起来的。
描述进程的结构体称为进程控制块(PCB),它是一个非常大的结构体,里面有许多的属性,(不是对象的原因是一般主流的操作系统是通过c语言来编写的,少数由c++编写)。
因此进程的生命周期是与PCB的状态密切相关的:
进程的生命周期:
- 创建进程:创建一个PCB,初始化进程的各种属性信息,将此PCB加入到链表中去。
- 销毁进程:从链表中找到对应的PCB,将此PCB从链表中删除。
- 查询进程:将指定进程的PCB的一些关键信息显示出来。
关于PCB的一些关键信息:
- pid —进程标识符
此属性用于标识每个进程。
如:下面联想程序的每个进程都有自己的PID
- 内存指针(一组):
进程需要在内存中找到要执行的指令在哪里,要使用访问的数据又在哪里,所以需要一组指针来指定内存中的位置。
程序执行的过程:
系统会将程序员编写的代码文件最终编译成.exe 文件(可执行文件)
.exe文件中包含着可执行的二进制指令与这些指令运行过程中所依赖的数据,这个.exe是保存在硬盘上的文件。
我们点击运行这个.exe文件时,如:
此时操作系统便会创建进程,并将.exe文件中的指令与数据放入到内存中去,当进程运行时,则从内存中的指令区域找到对应的指令一条一条地进行执行。
- 文件描述符表:
进程在内存中运行时,是可能与硬盘,网卡等进行交互的【因为有时进程所需的数据不会全部地加载到内存中,只是在需要时,再进行访问对应文件】当进程打开一个文件时,即将此文件的信息存入到文件描述符表中。
在操作系统中,会将很多资源当做文件来进行管理,而不只是硬盘上的文件,如网卡。
注:进程会访问硬盘资源,cpu资源,内存资源等,进程是操作系统分配资源的基本单位!
- 进程的优先级
进程的状态
进程的上下文
进程的记账信息
这四个PCB中保存的属性是关于进程调度相关的信息。
什么是进程调度? :
进程调度是操作系统进行管理进程时的重要工作,在我的电脑中有数百个进程
而我的cpu内核只有6个
一个cpu内核在一时只能处理一个进程中的一个指令。那操作系统是如何运行这数百个进程的?
在早期的计算机:计算机上的系统是"单任务系统",一次性只能处理一个进程,如果要执行其他的进程,就必须停掉上一个进程,
在后面的"多任务系统"中,即使cpu只有一个核心,也可以执行多个进程
此时采用的是分时复用:即一段时间内执行这个进程,另一段时间内执行另一个进程,但在用户看来,好像cpu一直在执行自己的这个进程。这种进程执行的方式我们称为并发;
在现代的cpu中,一个cpu中有数个内核,如上图6个内核,可以真正地同时运行多个进程,这种执行方式我们称为并行,当然,仅仅靠并行的方式是不够的,操作系统实际上同时采用并行与并发方式。
因为操作系统需要并发执行,所以需要进程之间的来回切换,则需要调度,如果要执行的进程过多,则会出现卡顿的情况,所以电脑卡顿并不是因为硬盘占用过多,而是因为内存中需要执行的进程,程序太多。
我们继续阐述PCB中的这四个进程调度的属性:
进程的五种状态:
就绪状态:进程除了cpu,其他资源都已准备好的状态(PCB,内存,栈内存,堆内存)
执行状态:进程获得包括cpu在内的全部资源,程序正在执行!
阻塞状态:指正在执行的进程,突然遇到某种情况(如:I/O请求,申请缓冲区失败等)暂时无法 继续执行下去,此时系统将处理机交给另一个就绪进程,而受阻进程的暂停状态称为阻塞状态。
创建状态:创建状态指进程除cpu外,所需的资源尚不能满足,此时的进程不能够调度运行,所以称其为创建状态
终止状态:进程由系统清理或者归还PCB的状态
进程的优先级:
在调度进程时,并不是任意调度的(即占用cpu的机会并不是均等的),而是有相应的优先级,优先级的标准各种各样,这里不一一列举,比如:
在玩某类电脑游戏时,如果此游戏比较注重即时性,则会占用更多的cpu资源,而如QQ,晚接收几秒钟信息则无关紧要,所以此游戏的优先级就比QQ的优先级高。
进程的上下文:
进程在调度中,是一段时间内占用cpu,一段时间内又不占用cpu,当重新回到cpu时,进程不能从头开始执行,需要找到上一次执行的位置。
在cpu的寄存器(一般cpu有许多寄存器)中保存着当前进程的“中间状态”,
如执行到了哪条指令,函数的调用关系等。当然还保存中间结果。
当停止执行当前进程时,则将当前cpu中的寄存器中的值保存到内存中去即PCB属性中去(因为PCB是内存中的结构体)称为:保存上下文。
当要重新执行此进程时,则将此PCB属性中的值再传到cpu的寄存器中去,称为恢复上下文。
进程的记账信息:
统计功能,用于统计每一个进程在cpu上的运行时间,如果发现某一个进程长时间没有占用cpu资源,则将cpu资源将其倾斜一些。
线程:
线程概念与一些问题
线程实际上才是cpu执行的基本单位,进程不是。
进程与线程的关系为:
进程包含多个线程,多个线程共用进程中的资源。
既然线程才是cpu执行的基本单位,那么进程中的信息又是怎么回事?
对于每个线程,都有各自独立信息—(优先级,状态,上下文,记账信息)
而对于进程的内存指针,文件描述符表则被其内部所有的线程所共用。
之所以在进程中引入线程的概念:
是为了可以并发执行程序而又可以节省资源(即内存指针,文件描述符表等资源可以被共用)。
创建线程—代码实现
线程与进程均是操作系统提出的概念,操作系统提供了一些api(Application Programming Interface)应用程序编程接口【api实际上就是别人写好的函数或类,可以直接拿来使用。api的广义的概念:操作系统会提供,标准库,第三方库,别人项目中代码等】提供给程序员使用。
Java将操作系统提供的api统一封装成Thread类,供程序员进行使用。
创建进程
方法一:
创建一个子类继承Thread类,然后重写run方法
class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("Hello Mythread");}}
}
public class Test {public static void main(String[] args) {Thread t = new MyThread();//创建了一个新的线程t.start();while (true) {System.out.println("hello world");}}
}
代码解析:在上述的代码中main方法是一个线程,t.start方法又创建了一个新的线程。这两个线程轮番被cpu执行
方法二:
先实现Runnable接口,然后重写run方法。
然后传参创建Thread类对象
class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("Hello Mythread");}}
}
public class Test {public static void main(String[] args) {/* t.start();*/Runnable r = new Runnable() {public void run() {while (true) {System.out.println("Hello Mythread");}}};Thread t = new Thread(r);t.start();while (true) {System.out.println("hello world");}}
}
总结:这两种方法区别在于是将线程要执行的任务的定义是放到Thread类中,还是类外即runnable接口实现类中,后者的代码耦合性较低(耦合性即指代码之间的关联度,我们理想不同模块之间的代码耦合性越低越好,这样代码出现错误改一处即可而不会改一片)。