JavaWeb 基础知识(一)——计算机是如何组成的

一、冯诺依曼体系(Von Neumann Architecture)

现代的计算机, 大多遵守 冯诺依曼体系结构

在这里插入图片描述

那么冯诺依曼体系究竟是什么呢?

  冯诺依曼提出了计算机结构体系的一个设想,规定了计算机大概要有什么设备,还有计算机要使用二进制等等…,后人为了纪念这个伟大的人物,就将这个计算机体系定义为冯诺依曼体系.

在这里插入图片描述

  看完了这个冯诺依曼体积的结构图,估计大家并没有真正的理解,所以带着大家分别简单了解一下各个部分…

1、CPU(中央处理器)

在这里插入图片描述

CPU是当今人类社会科技的巅峰之作

在这里插入图片描述

每一台电脑的中央指挥大脑就是CPU中央处理器,他是电脑上必不可少的设备

  上面的图片就是电脑上关于CPU 的相关信息,2.90GHz 这就是CPU的主频,CPU主频衡量了CPU执行速度的快慢,主频的数字越大,CPU运行的也就越快.

不知道大家有没有听过摩尔定律(不是我们在高中化学里学到的那个摩尔,咱说的摩尔是Inter公司的联合创始人)

摩尔定律:每18个月,芯片(CPU)的集成能力就增加了一倍,算力提升一倍,成本降低一半

不过现在摩尔定律已经濒临失效了,Intel现在但也被大家成为“挤牙膏的”,CPU 的算力达到一定程度,再想提升只能向挤牙膏一样慢慢提升,要想让集成程度增加,就需要单个计算单元变小…但是小不能无限小,达到普朗克级别,就不行了.

接着上面的说,CPU 是怎样工作的?

  一个CPU上面其实包含了很多的基本运算单元,每个单元其实就是一个’门电路’,如果有的同学在大学里提前接触过“数字电子技术”‘模拟电子技术’这两门专业课的话,可能对门电路这个词比较熟悉…

给大家简单介绍一下吧,大家可以简单了解一下不必深入研究。

门电路 所有的东西是从一个电子开关开始的

在这里插入图片描述

  不用看着图片去理解,我们只需要知道通过电子开关,我们可以实现 1 位(bit) 的看似无用的逻辑运算,但至少它工作起来了,不是么。怎么使用电子开关组合出真正有用的逻辑组件,我们接来下会做进一步的学习了解。

  接下来,我们学习如何使用电子开关构建一些有用的部件 —— 门电路。我们可以通过硬件可以来实现 1 位(bit) 的基本逻辑运算

非门电路

在这里插入图片描述

这就是非门电路的电路图,大家如果看不懂的话,只需要知道 通过这个电路,如果计算机输入了一个0,输出的是一个1,如果计算机输入的是一个1,那么输出的是一个0

与门电路

在这里插入图片描述

这就是与门电路的电路图,这其实相当于编程里的 && 运算,通过这个电路,输入1 输入2 都输入 1 ,输出1 。 如果输入1、输入2有一个输出0,那么输出 0。 同真则真,一假则假。

或门电路

在这里插入图片描述

这就是或门电路的电路图,这其实相当于编程里的 || 运算,通过这个电路,输入1 输入2 都输入 0 ,输出0 。 如果输入1、输入2有一个输出1,那么输出 1 . 一真则真,同假则假。

异或门

在这里插入图片描述

这就是或门电路的电路图,这其实相当于编程里的 ^ 运算,通过这个电路,只要输入的不一样(一个0,一个1), 那么输出1,如果输入的相同(都为0、都为1), 那么输出0 。 这个就是异或的规则: 同0异1

  我们代码中写的程序进行运算时本质上就是通过一个个门电路进行运算的,只不过CPU里面电路怎么搭建的,我们不去进行深究。

算数逻辑单元

CPU里面有一个非常核心的组件,叫做算数逻辑单元(ALU)

ALU 是计算机中进行算数、逻辑运算的核心部件,是计算机的数学大脑。ALU就是用一个个逻辑门电路构建的.

(1)算数单元

基于我们刚才了解的几个逻辑电路,我们就能够实现两个东西(半加器、全加器)

半加器

在这里插入图片描述

作用:进行两个1bit 位数的相加,最后输出的结果也是两个bit位的,一个bit位代表他们的和,一个bit位代表他们是否要进位.

  这要比刚才的门电路考虑的要稍微复杂一点,这个半加器不光要考虑 两个数的和,还要考虑 是否要进位…,所以这就不是单纯的按一个bit位来进行运算了,我们运用一个 与运算和异或运算就可以实现这样的效果.

还有一个东西叫做全加器

在这里插入图片描述

  全加器的作用: 对三个bit位进行相加,从它的构成图我们可以了解到,全加器是通过两个半加器进行一组合,也是能运算出一个两个bit位的结果,一个bit代表他们的和,一个bit代表是否要进位

有了半加器和全加器 ,我们对他们一组合,我们就能得到一个8位数加法器

在这里插入图片描述

所以8位加法器就是针对两个8bit位的数字进行加法操作

小结:

  通过门电路,可以构建出 半加器(针对2bit相加=>和、是否进位 )和 全加器(针对3bit 相加=> 和、是否进位)

  结合半加器和全加器,就能构建出一个加法器(针对两个 8bit位的数字进行相加)

在这里插入图片描述

计算机其实在计算加减乘除的时候,都是靠加法器~

加法器能算的不仅是加法,还能算减、乘除运算(C语言在介绍数据在内存中的存储介绍过)

数据在内存中的存储 原码反码补码 为啥计算机要存补码? 目的就是为了把加法和减法都统一成加法

  算术单元支持的操作当然远不止这些,通过继续组合逻辑门,算数单元可以做到加减乘除甚至更多的算术运算,但一个加法器作为演示已经足够了。实际上,乘法器和除法器的制作难度是要高于加、减法器的,有兴趣的同学可以尝试做更多的了解。

(2)逻辑单元

逻辑单元主要用来进行逻辑操作,最基本的操作就是 与、或、非操作,但不只是一位(bit)数的比较。

在这里插入图片描述

针对一个8bit位的数字判断是否为0

  他的判断也很简单,就是每两位进行判断或,最终看这个结果是0 还是非0就行了

那么有同学就会问了,怎么判断数字是 非0呢?

也很简单,在这个判断0的电路之前接一个取反的电路就行了

CPU ==> ALU ==> 加法器+ 逻辑判断

上面给大家介绍了 CPU,下面大家了解一下 存储器

2、存储器

在这里插入图片描述
在这里插入图片描述

说到存储器大家可能想到 内存和外存

内存: 平时说的内存

外存: 平时说的 硬盘、软盘、光盘、U盘

我们平时买一个手机,卖家说我这个手机是 128G 内存的,这个128 G说的是内存吗?我们说的这个内存说的其实是外存,那么什么是内存呢? 手机这里还有一个是 8G运存 6G运存,这个运存严格意义上就是我们所说的内存

内存比较小,外存比较大

内存访问速度快,外存访问速度慢(3-4 个数量级)

如果CPU从内存读数据的时间是1 ,那么从外存读数据时间就是10000

我们以后在学习过程中会经常提到一个词

持久化存储

存在内存的数据就不是持久的,只要掉电就丢失了 存在外存的数据就是持久化的,外存数据掉电不丢失

在上面我们基本了解了内存外存的基本结构

具体看看内存:

把内存想象成一个"大走廊" ,走廊上有很多房间~

每个房间的大小,是一个字节~ 每个房间也有一个门牌号

在这里插入图片描述

内存有一个非常重要的特点: 支持随机访问~

什么随机访问呢?

随机访问就是随心所欲的访问内存中的任意地址的数据,类似于”闪现“

  想象一下,我们在一个宿舍楼里面,宿管阿姨进行查寝,一般宿管阿姨是怎么查的呢?她从一个楼里面先从 101 开始查寝室 ,再查102、103 顺序的一个一个进行访问,但是呢,我们现在给宿管阿姨加上一个技能"闪现",就是说这个宿管阿姨,刚查完101 ,咔嚓一跺脚 跑到125 寝室了,在一跺脚跑到 210了,在一跺脚跑到5楼了,每次一跺脚都会一瞬间到达想到的房间里面,这件事再现实生活里面是不太靠谱的,但是在计算机里面确实现实存在的。

 计算机访问内存中的任意地址,所消耗的开销都极小

 相比之下呢,外存也有随机访问功能,但是外存的随机访问的代价要大得多,外存更擅长顺序访问

计算机存储数据,不仅仅是内存和外存能存储~ CPU上也能存数据(寄存器)

CPU的寄存器,存储空间更小,价格更贵,访问速度更快

 外存是持久化存储数据

 内存存的是当前这个程序所用到的数据

  CPU寄存器存的是当前正在进行的这组程序所涉及的运算的数据

  好了,以上就是给大家介绍的 CPU、外存、内存的基本介绍.

  至于说输入设备、输出设备更多的接近硬件,我们首要介绍的是与我们Java写代码关联较强的设备,就不过多的介绍其他的硬件了.

  咱们写的代码(C、C++、Java)最终都是在 CPU 上执行的

  这些编程语言写的代码会被编译器\解释器 ,转换成一系列CPU 认识的指令.指令的内容也是更加复杂,大家可以到《计算机系统结构》这本书进行了解这些内容.

二、操作系统(OS)

  操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows系列、Unix系列、## 标题Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。

操作系统是一个"搞管理"的软件

1、管理硬件设备

 比如说我现在有一个鼠标,我把这个鼠标查到电脑上,这鼠标就能用,为什么电脑能够识别这个鼠标?为什么我的鼠标以进行移动电脑桌面的指针位置就会发生变化… 之所以它能够进行操作,是因为操作系统能够识别这个设备,并且能够识别用户操作带来的信号或者消息

2、管理软件资源

管理文件 管理进程

所谓的管理就是说两个方面:

描述+组织

3、进程

process/ task 任务

"进程"其实是计算机完成一个工作的过程

进程在操作系统中是一个非常非常核心的概念

在我们电脑上就可以看到我们运行的各项进程任务

打开任务管理器

在这里插入图片描述

打开进程页面后我们可以看到 我们系统的进程,每一个进程都代表着一个正在运行的程序,或者换句话来说,进程就是一个正在运行的程序,这就是我们对进程的一个直观的认识

在这里插入图片描述

  我们在CPU处理器当中可以看到每一个进程后面跟着许多列(CPU、内存、网络、磁盘 等等),这些列都是我们系统能够提供的一些硬件资源,在换句话说,要想这个程序跑起来,就得给他分配一些具体的硬件资源

  要想让进程跑起来,就得给这个进程分配一定的系统的硬件资源: CPU、内存、磁盘、网络带宽

进程是系统分配资源的基本单位

三、进程管理

  关于进程,最核心的问题,就是进程在系统中如何被管理的?

管理 = 描述(PCB) +组织

描述PCB

PCB: 进程控制块,这是一个类、C语言的结构体

因为我们当前主流的操作系统,向Windows、Linux 等他都是用C语言或者C++来实现的

一个结构体对象 就对应一个进程

那么如何组织呢?

组织

  我们的系统内核中往往会使用一定的数据结构来组织,一种常见的做法就是 使用双向链表来 组织进程.

创建一个进程就相当于 去创建一个PCB结构体对象,把这个对象加到 内核的双向链表中

销毁一个进程就是把这个节点从链表中删除

我们查看进程信息,本质上就是遍历操作系统内核中的这个链表,并显示其中的属性

  接下来呢,我们来给大家介绍一下进程控制块 PCB里面到底有什么属性…

PCB属性

 PCB 中大概有哪些属性呢?我来给大家罗列一下…

1、pid

process id — 一个进程的身份标识

在这里插入图片描述

  一个系统上同一时刻不可能有两个进程的pid 是一样的,因为他就是一个身份表示的效果,如果有两个进程pid是相同的, 就不能代表唯一这个特性了

2、内存指针

描述了这个进程使用的内存空间是哪个范围…

3、文件描述符表

描述了这个进程都打开了那些文件

系统打开一个文件,其实也就打开了一个"文件描述符"

  这个文件描述符就像 一个"遥控器"一样.文件数据是在磁盘上的 ,代码中操作磁盘数据不像操作内存数据那么方便,所以往往是借助这种遥控器 的方式来操作。

  下面介绍的几个属性属于同一组,属于核心的属性,上面的了解就可以,接下来的几个属性我们不光要了解还要熟悉理解.

4、进程的状态 进程的优先级 进程的上下文 进程的记账信息

进程调度

这些属性是辅助进行 进程调度

我们的机器上有上百个进程在运行.

而我们的电脑上有几个CPU呢? 1个(8 core CPU)

多核的意思,把多个CPU捆绑打包在一起了,相当于我们的一个CPU有8个分身同时来干活

 8个分身同一时间只能做8件事情,但是我们电脑上有多少个事情要做,上百个!!

  所以我们发现当前对于我们的计算机来说,有一个很严重的问题,狼多肉少~ (进程太多了,CPU太少了)

我们现在使用的系统一般都是支持多任务的系统~

什么是多任务呢? 就是我们可以便开着爱奇艺看剧,还可以再开一个浏览器网页看新闻

  当前的这个"多任务系统",其实就是基于 "进程调度"这样的机制来完成的.

我们举一个例子来更形象的说明什么是进程调度吧

假如有一个长得贼好看的妹子,有很多追求者 正常来说,妹子只能和一个小哥哥交往~ 妹子能否做到,同时和多个小哥哥交往呢?

为了给大家带入情景,给一个设定,妹子为什么要找多个小哥哥交往呢? 因为这几个小哥哥都不能做到尽善尽美 A: 很有钱,但不帅 B:长得很帅 C:没钱,也不帅,但是很会讨女孩子欢心

只要安排好一个时间表,这几个小哥哥就不知道对方的存在

安排一个时间表: 周一上午:和A一起去逛街 周二下午:和B一起去吃饭 周三下午:和C一起去上课

从宏观上来看:(一年这样的时间维度来看)同时和多个小哥哥交往

从微观上来看:(一天这样的时间维度来看)妹子同一时刻就是在和有一个人相处

  大家思想可别拐走啊,咱不管这个妹子在生活里如何做到时间管理的,但是操作系统就是这么管理进程的~

1、并发式执行

  这样做就能做到我们刚才遇到的狼多肉少的问题(进程多CPU少),进程这么多,CPU这么少,怎么分配呢?靠的就是这张时间表.

  比如说我们电脑上有A、B、C三个进程,先把CPU分配给A,运行一会后,把A置换出来,把CPU分配给B这个进程,运行一会后,再运行C进程

从微观上来看,一个CPU同一时刻只运行了一个进程

但是从宏观上来看,一个CPU好像同时运行了三个进程

  这样的运行方式,我们称为"并发式执行",这是操作系统中运行进程的最核心的思想

  由于我们的CPU运行速度极快~虽然CPU一直在进行切换,但是咱们坐在电脑前的用户是感受不到这个切换到过程的

2、并行式执行

 除了并发式执行 ,还有一种运行方式,“并行式执行”

我们有多个CPU,运行多个进程

CPU1 运行进程1 CPU2 运行进程2 CPU3 运行进程3

  这种方式无论是在微观还是 宏观上都是同时执行的~

真实的计算机,真实的操作系统在进行进程调度的时候,是并发、并行两种策略综合使用的.

3、进程属性

  说完了什么是进程调度,我们接着上面 进程的几个属性来介绍

(1)进程的状态

当前的进程的状态

R(就绪状态) 随时能去CPU里面执行

S(睡眠状态) 睡眠什么意思呢? 就是当前进程可能要等待用户的一些输入,比如说在QQ聊天框 文本标进行闪烁,这就是进程在等待着用户的输入,什么时候输入也不知道,此时进程就处于睡眠状态.

X(结束状态) 进程运行结束

  如果还是不懂的话,我们在拿上面妹子的例子来说明:

如果这三个小哥哥都是随叫随到,就是就绪状态

比如A出差了,不在当前了,约肯定约不到,就相当于S状态,相当于现在约不到,但是过一段时间他回来了,还是能约到的~

比如妹子对C厌烦了,把他踹了,就相当于 X 状态,进程结束.

  进程状态是系统安排时间表的重要属性,这就是进程状态.

(2)进程的优先级

优先级的意思就是我们安排进程时间表的时候,看优先给谁安排.

还是拿上面的妹子举例子:

假如要安排一个一周的时间表,留出一天去休息,周一到周六我们来安排时间表按上午下午分,12块时间

这12块时间不一定是均匀分配

假如妹子最喜欢B, 给B分配6块时间 其次喜欢C, 给C安排4块空间 最不喜欢A(只图他的钱),分配给他2块空间

很有可能是按照这样的方式来分配的

  总之进程在调度的时候,每个进程在CPU中获取到的时间也不是完全均等的,有的进程分配的时间更多,那么被调度到CPU上的机会更多,有的进程可能会少,这多和少的差别就是进程的优先级

(3)进程的上下文

上下文就是 要记录上次运行到哪个指令了,方便下次调度的时候能够继续从这个位置来运行

就类似于游戏里的 读档和存档

比如有一天我和A 在逛街~ A 说咱们下周有空的时候去普吉岛完~ 妹子说好啊 等到下周的时候,再次见到A 的时候,就得提到这个事情

上下文的信息必须得整理好,要是把上下文的信息整茬了,那就穿帮了(????)

比如说妹子和A说好下周去普吉岛, 但是妹子下周和B见面说普吉岛的事情,那就穿帮了~ 为了不穿帮,就需要在小本子上,不光要记录时间表,也要记录约会的上下文~

那么具体到我们进程来说,进程的上下文主要来存什么呢?

  进程的上下文,主要是存储调度出CPU之前,寄存器中的信息(把寄存器信息保存到内存中),等到这个进程下次恢复到CPU上执行的时候,就把内存保存好的数据恢复到寄存器中.

进程本身是感知不到什么时候被调度出CPU的

(4)进程的记账信息

  记录这个进程在CPU上执行多久了,用来辅助决定这个进程是继续在CPU上执行,还是说要被调度出去了.

还是拿上面的例子来说

妹子排完时间表后,一看发现给A的时间块有点多了,B的也不少,C时间太少了,为了均衡一下A、B、C的时间,根据之前时间表的统计记录,把C的时间重新分配一下.

以上就是有关进程调度的几个属性.

进程调度的过程是非常非常重要的,对于我们后面写代码来说具有非常重大的指导意义!

操作系统何时进行进程调度?(啥时候把进程放到CPU上,啥时候把进程切换出CPU)

这个事情对于进程来说是感知不到的

执行到进程中的任意指令,都可能产生这样的调度 (抢占式执行)

  此时,这样的调度其实给我们的代码引入了一定的随机性,对于我们代码的正确性来说,就能产生新的挑战(可能我们原来写的代码是对的,但是一旦涉及进程的调度可能就不对了,这时我们的程序就不是那么好写了,这样的问题在后面多线程的时候会具体解决)

(5)进程的虚拟地址空间

一个进程要想运行,就需要给他分配一些系统资源,其中内存就是最核心的资源~

内存对于我们的进程来说起到至关重要的作用.内存这块是怎样进行资源分配的呢?

我们的系统并不是给进程分配了真实的物理地址,而是分配了一个虚拟地址,什么意思呢?

物理地址:真实的内存地址

在这里插入图片描述

而现实中的系统是怎样分配内存呢?

在这里插入图片描述

  有同学可能就会问了,分配的地址一样,那内存空间不就重叠了?

其实并没有重叠!

这里的地址都是操作系统抽象出来的虚拟地址 系统会自动把这个虚拟地址转换成真实的物理地址.

  我们分配给进程的只是虚拟地址,虚拟地址再根据一种数据结构(页表)来找到真正的物理地址,所以虚拟地址是否相同,也就不重要了.

在这里插入图片描述

这样的映射关系,就像在学校给班级同学进行编号一样.

比如我针对100班的同学进行编号1—30 我在针对76班的同学进行编号1—50 两个班的1号明显不是同一个人啊,虚拟地址和物理地址就相当于这样的映射关系

那么为什么要搞出虚拟地址空间这个东西,为啥不让进程直接访问真实的物理地址?

目的就是为了一定程度的减少内存访问越界带来的后果~

什么叫做内存访问越界?

比如说 进程1的内存范围 0x100 — 0x800 如果我的代码尝试修改 0x801地址的数据,这个操作就是越界访问(错误的操作) 如果这是一个真实的物理地址,这个修改就真的把 0x801给修改了~ 如果这个0x801正好是进程2要使用的内存,此时进程2就可能出bug了,就直接崩了~ 如果进程访问的是虚拟地址,也尝试修改0x801 此时系统就要针对0x801来查询页表,找到对应的物理地址 由于0x801已经是非法地址,在页表当中查不到~~系统就明白了,这是在越界访问 于是就让这个进程直接崩溃,防止影响到其他进程.

这样的操作就让进程和进程之间影响到的可能性变小了,隔离性增加了,进程也就更稳定了

  我们分配地址时多一层映射肯定要低效了嘛,分配会更麻烦,效率会更低,但是我们还是得这么做,因为这样做带来的好处太明显,能让程序更稳定,能让我们出现越界访问这样的操作时更容易的找到出现的问题。

  总之虚拟地址起到的效果就是如果某个进程越界访问,不至于影响到其他进程的情况,所以这就是我们引入虚拟地址空间的必要性

好处:让进程之间的独立性提高了,不至于相互影响,整个系统更加稳定了

缺点:当两个进程需要相互配合的时候,沟通起来就困难了.(进程间通信)

进程1和进程2由于虚拟地址空间(进程的独立性),导致很难进行相互访问对方的内存

如果要想相互交流沟通,就需要使用一些特殊的手段(借助某个双方都能访问的东西进行交互)

方式有很多例如:

文件、管道、消息队列、信号量、信号、socket

了解即可,不过多介绍了..

  关于进程相关的知识就先将到这了,下一节会讲到线程相关的知识,希望大家多多练习,今天先讲到这里了.

谢谢欣赏!!!

敬请期待…JavaWeb 基础知识(二)——线程01

未完待续…