概述
课前导读:
本篇是关于计算机工作原理和多线程编程的解读,主要包括计算机发展背景、图灵大佬生平、冯诺依曼体系结构、cpu与Gpu、电路门、CPU具体的特点、编程语言、Java的前世今生、操作系统、进程的概念、内存管理、进程间通信、线程与进程的区别、线程代码的实现等
目录
课前导读:
一、计算机发展史
1、简介
2、冯诺依曼体系结构
3、门电路
4、编程语言
二、操作系统
1、简介
2、操作系统的定位
3、进程
4、内存管理
4、进程间通信
三、进程和线程
四、线程的代码(Thread)
总结
一、计算机发展史
1、简介
世界上很多的高科技发明,主要是为了军事用途,计算机刚开始研发出来是为了计算弹道导弹的轨迹,国之重器,非常重要,两弹一星(氢弹、原子弹、卫星),但是计算过程非常复杂,计算量非常大,一开始用算盘来计算,但是算的又慢又不准,所以有了计算机的研发。
于是产生了世界上第一台计算机:埃尼阿克,诞生于1946年,在美国普林斯顿大学,运算速度(cpu主频) 5000hz(每秒5000次),重达几十吨,占地面积好几个房间。后来有了通用性计算机,愿景是由英国的图灵大佬提出,后面由美国的冯诺依曼设计实现。
图灵大佬在英国和德国的战争(诺曼底登陆)中破译了德军的engima加密,贡献卓著,但战后却遭受到了政府的迫害,就因为他是个男同(弯的),是宗教所不能容忍的,政府对他进行了化学阉割,最后图灵大佬郁郁而终,享年41岁。后在2013年,英国伊丽莎白女王为其平反,计算机最高奖项为图灵奖!
2、冯诺依曼体系结构
2.1、CPU(通用计算机芯片):CPU是计算机最核心的部分,进行算术运算和逻辑判断的,CPU是当前人类科技的巅峰之作,可以和氢弹的制作媲美,CPU造的最好的就是美国,全世界的计算机绝大多数使用的是这三个品牌:Intel、AMD、高通。CPU难的不是理论,而是工艺,Intel和AMD已经可以研发出5nm制程的CPU了,CPU内部有复杂的结构,单个组件尺寸大概就是5nm左右,尺寸越小,集成的内部主键就越多,CPU运算速度就越快,尺寸小到了一定程度,就脱离了经典力学的程度,量子力学开始接管了,所以后面的路任重道远。
2.2、输入设备:键盘、鼠标、麦克风、摄像头;输出设备:显示器、音响等;有的设备既可以输入也可以输出,比如触摸屏和网卡。
3、门电路
主要包括:与门、或门、非门,借助二极管等设备特殊物理属性实现
4、编程语言
编程语言是程序员和计算机之间沟通的桥梁,编程语言必须严谨且无歧义。
世界上上的计算语言可以分为三类:
1、机器语言:二进制(01)构成的指令,在CPU中使用。一般厂商在设计CPU的时候就会设计好“指令集”,CPU都支持哪些指令,以及这些指令要怎么工作,这就类似于CPU中提供的API供机器使用。
2、汇编语言:通过简单的单词作为助记符,代替二进制的指令,每一个的机器指令,就能对应到一个汇编语句。不同的CPU有不同的体系架构,支持的指令集也不同,即使是同类架构,不同版本,指令集也是不同的,这就导致了汇编语言的不同了,所以我们学习汇编语言的时候,一定要明确你学的是针对哪个系列的CPU。CPU的架构有:x86,arm,mips等。当下主流的PC和服务器都是x86结构,手机、路由器主要是arm结构。
3、高级语言:(c,c++,c#(sharp)),c++在c的基础上改进,c#在c++的基础上改进,但因为c#被微软搞了和windows的捆绑销售,所以市场占有率极地。
还有JAVA、python、php,PHP是世界上最好的语言(梗),PHP之前官网上自己写的(嘻嘻嘻);也有中文语法的编译器,比如易语言、丙正正,但是中文难打,开发效率极低。
Java的前世今生:最早Java诞生,是用来做嵌入式开发的,老外的智能面包机,但是太拉胯了就没开发成,后来进行网页开发(applet),主要用来开发网页,开发动态网页,实现网页和用户之间的交互操作,做的风生水起;后来Java遭到微软封杀,因为微软当时开发了一个最厉害的浏览器(IE浏览器),IE和windows系统捆绑销售,因为微软要扶持自家的编程语言(VBScript),就把Java打凉了,但微软的编程语言太弱了,这就让JavaScript躺赢了,成为了前端开发最主流的选择(199x年),直到30年后的今天,才被微软的TypeScript取代 。后来Java兵分两路,一边进行后端开发,一边进行嵌入式开发(手机程序),J2ME技术,发展很好,但后来2007年苹果手机的问世,传统诺基亚手机就凉了,就使JavaME就凉了,而且传统的PHP做复杂网站容易把界面和业务逻辑混合到了一起,从巅峰跌落到了低估;后来Java进军移动端的安卓,安卓的原生语言选择了Java,本来谷歌要把Python作为原生语言的,但是因为Python作者龟叔的离职,没有选择Python,使Java崛起,安卓开发就让原来Java开发J2ME的程序员来快速的构建出了安卓的生态,很快安卓就成为了世界上第一操作系统。谷歌赚麻了,于是出现了经典的甲骨文版权费之争(因为安卓底层是Java实现的),甲骨文把谷歌告上了法庭,最后谷歌败诉赔了天价版权费,现在谷歌正在搞新一代移动端操作系统和新的编程语言,就是为了脱离原来Java的版权控制。后来Java在后端领域发力,Spring社区崛起,成为了后端开发的主流语言之一,最终Java在如今虎踞编程榜的榜一位置!
二、操作系统
1、简介
操作系统就是个软件,搞管理的软件,对下要管理硬件设备,对上要给软件提供稳定的运行环境,操作系统是软件和硬件和用户之间交互的媒介;
计算机用户最熟悉的操作系统:Windows系统:windows98,2000,xp,vista,win7,win10,win11等等;
程序员需要掌握的操作系统:Linux,特别适合与进行开发和部署;用于服务器、嵌入式设备和移动端设备的开发等
苹果电脑用的系统:Mac系统,但是挺难用的。
手机上的系统:Android(本质上也是Linux),ios和mac是同源。
2、操作系统的定位
2.1、硬件设备:指的是电脑中能看见的东西,后盖打开里面都是硬件设备。
2.2、驱动程序:硬件厂商在开发硬件的同时会提供驱动,电脑装了对应的驱动,才能让系统正确识别硬件设备,用于和硬件的通信。
2.3、操作系统内核:核心功能是对上和对下的管理
2.4、系统调用:操作系统给应用程序提供的api。比如:有个程序想要操作一下硬件设备,就需要先通过系统调用,把操作命令告诉给系统内核,内核调用驱动程序,进一步操作硬件设备。
3、进程
一个跑起来的程序,就是一个进程,进程(process)也叫作任务(task)。
作业(job):这个术语比进程更抽象一层,你可以说process是job的一种具体实现,job也不一定全是process。
句柄(handler):系统中包含很多的软件资源(进程就是一种软件资源),写代码的时候需要用到这些软件资源,软件资源就是在操作系统内核里的,在应用程序代码中,不方便操作。句柄就好比一个遥控器(简单的证书编号),通过系统借助这个句柄就可以操作软件资源了。指针也可以视为一个句柄,对应的是内存资源。
打开任务管理器,里面对应的就是你计算机上的进程了,每个进程对应一些资源,进程是操作系统资源分配的基本单位。进程是一个重要的软件资源,是由操作系统内核负责管理的。
进程的描述:使用结构体(c语言的结构体)来描述进程属性,操作系统基本上用c/c++来写的,为了描述这个结构体,起了个名字,PCB(进程控制块)。
进程的组织:通过双向链表(结构比双向链表更复杂),来吧多个PCB给串到一起。创建一个进程,本质上就是创建一个PCB这样的结构体对象,把它插入到链表中;销毁一个进程,本质上就是把链表上的PCB节点删掉;任务管理器查看进程列表,本质上就是便利这个PCB链表。
PCB:
1、PID,进程的身份标识符(唯一的数字);
2、内存指针,指向了自己所在的内存;
3、文件描述符表,硬盘上的文件等其他资源;
4、进程调度的相关属性:
(1)进程的状态:就绪状态:随叫随到,进程随时准备好了去CPU上执行;运行状态:正在运行;阻塞状态:短时间内无法到CPU上运行;
(2)优先级:进程也是有优先级的,操作系统进行调度并不是一碗水端平的;
(3)上下文:操作系统进行进程切换的时候,就需要把进程执行的中间状态记录下,保存好,下次这个进程再上CPU上运行的时候,就可以恢复上次的状态继续执行。进程的上下文就是CPU中的各个寄存器的值,寄存器是CPU内置的存储数据的模块,保存的就是程序运行过程中的中间结果。保存上下文,就是把这些CPU存储器的值,记录保存到内存中;回复上下文,就是把内存中的这些寄存器值恢复回去。
(4)记账信息:操作系统会统计每个进程在CPU上占用的时间和执行的指令数目,根据这个来决定下一阶段如何调度。
系统中的进程很多(上百个),但是CPU只有一个,虽然现在的CPU都是多核CPU,但是还是会出现“狼多肉少”的情况,我们希望这些进程能够同事运行,“分时复用”。
并行:微观上同一时刻,两个核心上的进程,就是同时执行的。
并发:微观上同一时刻,一个核心上只能运行一个进程,但是它能够对进程快速的进行切换,2.5Ghz 每秒运行25亿条指令,人们宏观上感知不到,感觉就好像好多个进程同时运行。
4、内存管理
内存其实是虚拟地址空间,程序中所获取到的内存地址,并非真实的物理内存的地,而是经过了一层抽象虚拟出来的地址;
内存条:
内存条中的各个编号就是真实的物理地址,内存支持随机访问,访问内存上的任意地址,速度都极快,时间都差不多是o(1)。
应用内存的真实物理地址的情况:
但是如果进程1代码出了bug,数组访问越界了,就可能会访问到了进程2的地址,就把进程2中的内容更改了,就会使进程2出问题,就会使其他程序崩溃,所以我们需要用虚拟地址把内存空间进行隔离,代码里不再直接使用真实的物理地址了,而是使用虚拟的地址,由操作系统和专门的硬件设备负责进行虚拟地址到物理地址的转换。
一旦其中的内存访问越界了,操作系统内核就会发现这里的地址,超出了进程1的访问范围,此时会反馈一个错误,发送一个SIGN SEGEMENT FAULT的信号来引起进程的奔溃,谁出bug了就谁崩溃,不会影响到别的进程。
4、进程间通信
进程因为虚拟地址进行了隔离,但是有的时候需要各个进程之间进行数据的交互,所以我们在隔离性的基础上,开了个口子,需要搞一个多个进程都能访问刀的“公共空间”,基于这个公共空间来进行数据的交互,这里的公共空间的实现主要是两种方式:基于文件、基于网络
三、进程和线程
并发编程:应用进程是为了解决并发编程的问题,所谓并发编程就是因为目前CPU进入了多核时代,要想进一步提高程序的执行速度,就需要充分的利用CPU的多核资源,所以我们需要把CPU充分利用上。
目前来说,多进程编程已经能解决并发编程的问题了,已经可以利用CPU的多核资源了,但是进程的创建、销毁和调度的开销太大了,消耗资源多且速度慢(主要是慢在了资源分配的问题上),因此线程就诞生了。
线程:也叫“轻量级进程”,线程比进程在解决并发编程的问题上更加快速,线程能够有效的节省申请资源和释放资源的操作。
线程和进程的关系:
1、进程包含线程!一个进程可以有多个线程,也可以只有一个线程,但进程中不能没有线程,当第一个线程启动的时候,就会向内存申请资源,后续线程的启动就不用再申请资源了,同一个进程里的多个线程之间,共用了这个进程的同一份资源(只要是指内存和文件描述符表);
2、操作系统进行调度的时候,是以线程为单位进行调度,如果每个进程有了多个线程了,每个线程是独立在CPU上进行调用的,(线程是操作系统调度执行的基本单位),每个线程有自己的执行逻辑;一个线程是通过一个PCB来描述的,一个进程里面可能对应一个PCB也可能对应多个PCB,在于进程数量的多少;PCB里面的状态、上下文、优先级、记账信息都是每个线程都是自己独有的,但在同一个进程中的PCB之间pid、内存指针、文件描述符表是一样的。进程专门负责资源分配,而线程专门负责接管和调度相关的操作。
线程安全问题(多个执行流访问同一个共享资源的时候):
1、增加线程的数量的时候,也不是一定能提高运行速度的,CPU的数量有限,过多的线程就会使其浪费,线程太多,核心数目有限,不少的开销反而浪费在了线程调度的问题上了;
2、如果线程多但是处理的问题少的情况,就可能出现一个线程抛出异常,处理不好的情况下就会使整个进程崩溃。
四、线程的代码(Thread)
1、继承Thread对象,重写run方法
//一、继承 Thread, 重写 run //创建线程的第一个方法,通过创建子类对象继承thread,调用start方法进行线程的创建 class MyThread extends Thread{ @Override public void run() { while(true){ System.out.println("hello world"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class threaddemo1 { public static void main(String[] args) { //创建一个线程对象 Thread t=new MyThread(); //start创建了一个线程,由新的线程来执行run方法, //具体就是调用了操作系统的API,通过操作系统内核创建新线程的PCB,并且把要执行的指令交给这个PCB //当PCB被调度到CPU上执行的时候,也就执行到了线程的run方法里了的代码了。 //执行完毕立即销毁 t.start(); while (true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
2、实现Runnable接口,重写run方法
//二、实现 Runnable, 重写 run //第二个方法,通过创建子类对象实现Runnable接口,重写run方法,再通过主类实例化对象创建任务,通过线程对象调用任务 //优点:降低了耦合性,如果需要应用进程或线程池等对象时就不需要修改任务了 class MyRunnable implements Runnable{ @Override public void run() { System.out.println("hello"); } } public class threaddemo2 { public static void main(String[] args) { //通过实例化myrunnable对象,创建一个任务给线程 MyRunnable myRunnable=new MyRunnable(); //创建线程对象,通过start方法创建线程 Thread t=new Thread(myRunnable); t.start(); } }
3、继承Thread对象,重写run方法,通过匿名内部类实现
//三、继承 Thread, 重写 run, 使用匿名内部类 //通过thread的匿名内部类实现 public class threaddemo3 { public static void main(String[] args) { Thread t=new Thread() { @Override public void run() { System.out.println("hello"); } }; t.start(); } }
4、实现Runnable接口,重写run方法,通过匿名内部类实现
//四、实现 Runnable, 重写 run, 使用匿名内部类 //通过匿名内部了实现了Runnable接口,重写run方法 public class threaddemo4 { public static void main(String[] args) { Thread t=new Thread(new Runnable() { @Override public void run() { System.out.println("hello"); } }); t.start(); } }
5、通过Lambda表达式实现
//五、使用 lambda 表达式 // 通过Lambda表达式创建线程对象 public class threaddemo5 { public static void main(String[] args) { Thread t=new Thread(()->{ System.out.println("hello111"); }); t.start(); } }
注意:以上线程的创建都是在调用thread对象使用start方法时才创建,其他的只是创建了一个实例化对象。
总结
以上很多理论知识,枯燥无味,但确实支撑我们多线程编程必不可缺的理论基础,所以我们必须熟练掌握!
所有成功的开始还得基于牢靠的基础,努力学习,坚持编码,编程伴随每一天!
最后
以上就是端庄小鸭子为你收集整理的计算机工作原理及进程和线程的区别课前导读:一、计算机发展史二、操作系统三、进程和线程四、线程的代码(Thread)总结的全部内容,希望文章能够帮你解决计算机工作原理及进程和线程的区别课前导读:一、计算机发展史二、操作系统三、进程和线程四、线程的代码(Thread)总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复