JAVAEE-1

进程与线程

操作系统 

操作系统是一个软件,~~(由代码构成程序)

操作系统的职责:

1.管理硬件各种设备

2.给其他软件提供稳定的运行环境~~

将上面这两种功能进行抽象和封装

进程/任务(Process/Task)

进程就是操作系统,提供的一种"软件资源"

目前市面上的系统都是多任务操作系统,同一时刻可以同时运行多个任务.

与之相对应的是单任务操作系统,只能在同一时刻运行同一个程序

我们所说的进程主要是对于多任务系统来说的.

每个任务/进程在执行过程中,都要消耗一定的硬件资源

换而言之,计算机的每个进程,在运行的时候,都应该分配一定的系统资源

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

操作系统中的进程管理

1.先描述(先试用类/结构体这样的方式,把实体属性全部列举出来)

表示进程信息的结构体,称为PCB(进程控制块,Process Control Block)

具体在Linux上,PCB是一个叫做struct task_struct{........}这样的结构体

2.再组织(使用一定的数据结构,将这些类/结构体/对象,连接在一起)

  在Linux中,使用链表的数据结构将若干个task_struct给串起来.~~

当我们看到任务管理器中的这些进程的时候,意味着系统内部就在遍历链表,并且打印每个节点的相关信息;

如果运行一个新的程序,系统就会多出一个进程,多的这个进程就需要构造出一个新的pcb,并且添加到链表上.

如果某个运行中的程序,退出了,就需要把对应进程的pcb从链表中删除,并且销毁对应的pcb资源.

PCB这个结构体,有上百个属性.

接下来简单介绍一下最核心的属性

pid

进程的身份标识

系统会保证同一台机器,同一个时刻,每个进程的pid都是唯一的.

(后续再对进程进行操作的时候,只需要操作对应的pid即可)

内存指针(一组)

内存指针描述了进程使用内存资源详细情况~~

进程运行过程中,是需要消耗系统的一些资源的.其中内存就是一种最重要的资源

在系统中,内存不是随便使用,都需要先申请,再分配,你才能使用

每个进程,都必须使用自己申请的内存空间.

内存指针,就是用来描述说你这个进程,都能使用哪些内存

一个进程"运行起来"是需要知道有"指令"和"数据"(指令和数据,都是需要加载到内存中的)

进程也需要知道,哪里存的是指令,哪里存的是数据.

双击一个exe,就会运行程序,加载的过程,就是系统先把exe文件里的内容(包含了指令和数据,先加载到内存当中)然后再创建进程,让进程开始执行.

文件描述符表

描述了进程所涉及到的硬盘相关的资源

操作系统,把所有盘都抽象封装成了文件

因为我们的进程需要经常访问硬盘,所以操作系统对于硬盘这样的硬件设备进行了封装=>~~

一个进程想要操作文件,就需要先打开文件,就是让你的进程在文件描述符表中分配一个表项(构建一个结构体)表示文件的相关信息

进程是系统分配资源的基本单位.(内存,硬盘->就在PCB中有所体现)

一个进程消耗CPU,我们该怎样理解

我们可以把CPU看做是一个舞台,需要执行的指令就是舞台,把进程看做是演员

进程要执行指令

同一个时刻,同一个舞台,只能有一个演员上台

也就是同一时刻,同一个核心,只能有一个进程

假如现在有一个CPU,逻辑核心有16个,但是进程繁多,那么该怎么办.

我们用到了一个非常关键的概念,分时复用(并发)

关键要点-让多个舞台,轮流上台

CPU在只有一个核心的情况下,先让进程一执行一段时间,然后让进程1下来,让进程2执行,然后过一段时间,再让进程2下来,进程3上去,周而复始,只要我切换的速度够快,那么就相当于这么多的进程是同时执行了,当然如果系统进程太多了,负担太重,就会出现卡顿

随着CPU的发展,现在有四个舞台,同时就可以有4个不同的进程,在四个不同的舞台上同时进行,此时刺客,在微观上看,这几个进程是同时执行,不是依靠快速切换模式的"同时执行"

称为"并行执行"

当然,前面的并发执行也仍然存在,每个核心都要分时复用,仍要快速切换

两个进程是并行执行,还是并发执行,是需要看系统的调度的

实际情况中,我们往往把并发和并行统称为并发

通过并发来加快IO效率

PCB中就有一些属性,来支持系统完成对这些进程的调度

1)状态

用来描述某个进程是否能够去cpu上执行,有的时候,某个进程这会不太方便,你如Scanner ,你不知道用会什么时候输入内容,这是一个不可控的事情.

就绪状态:随时准备好去上CPU,操作系统,打一声招呼就可以了.

阻塞状态:这个进程,当前不方便去CPU上执行.不应该去调度他,(比如,进程在等待IO,来自控制台的输入 输出/硬盘输入输出/网卡输入输出)

2)优先级

多个进程等待系统调度~~

多个进程的调度总有一个先后顺序

先调度谁,后调度谁,谁长谁点都是可以进行调配的

记账信息

针对每个进程,占据了多少cpu时间,进行一个统计.会根据这个统计结果来进一步的调整调度的策略~~

因此,就需要在下一个轮次进行调整.

确保每个进程都不至于出现完全捞不着CPU的问题

上下文

支撑进程调度的重要属性,是PCB中的数据结构,

存档,需要在进程调度出cpu之前,把当前寄存器的这些信息,给单独保存到一个地方

读档,在该进程下次再去cpu执行的时候,再把这些寄存器的信息给恢复回来

操作系统调度进程,过程可以认为是随机的,任何一个进程,代码执行到任何一条指令的时候,都有可能被调度出cpu,在进程下次调度回cpu的时候,继续之前的进度来执行.

所谓的"保存上下文"就是把cpu的关键寄存器中的数据,保存到内存当中(PCB的上下文属性)

所谓的恢复上下文就是把内存中的关键寄存器中的数据,加载到cpu对应的寄存器中.

内存分配-------内存管理

进程如何管理内存是一个非常复杂的事情.后续再讨论

结论:每个进程的内存,是彼此独立的,互不干扰的.

通常情况下,进程A不能直接访问进程B的内存;

目的:为了系统的稳定性,如果某个进程出现bug(比如内存写越界)出错影响的范围,只是影响到自己这个进程,不会影响到其他进程,否则,要是系统上的一个进程崩溃,影响了其他进程,这是一个非常糟糕的事情.

我们把这种情况称为"进程独立性".

进程间通信

 虽然有进程的独立性,但我们有时候也需要多个进程相互配合,玩成某个工作,

进程间通信和进程的独立性并不冲突.

系统会提供一些公共的空间(多个进程都能访问到),让两个进程通过公共空间来交互数据.

java中,主要的进程间通信方式使用文件和网络.

线程.

多任务操作系统,希望系统能够同时运行多个程序~如果是单任务,不涉及到调度的问题

本质上来说,进程,是可以很好的解决并发编程这样的问题的.

在一些特定的情况下,表现的不尽人意

比如,在某些场景下,需要频繁的创建和销毁进程的时候,此时需要使用多进程编程,系统开销机会非常大.

我们实际的服务器在同一时刻会收到很多请求,对于每一个请求都会相应的创建一个进程,给这个请求提供一定的服务,返回对应的相应.一旦这个请求处理完了,此时这个进程就要销毁了.

如果请求过多,意味着你的服务器就需要不停的创建新的进程,也不停的销毁旧的进程.频繁地创建和释放.

这样进行操作,系统的开销是很大的.其中最关键的原因在于,资源的申请和释放,进程是自愿(cpu,硬盘,内存,网络带宽)分配的基本单位.

一个进程刚刚启动的时候,首当其冲就是内存资源

进程需要把依赖的代码和数据,从磁盘加载到内存中区.

从系统分配一个内存,不是一件容易的事情.

一般来说,申请内存的时候,需要指定一个大小,系统内部就会把各种大小的空闲内存,通过一定的数据结构,给组织起来了.实际申请的时候,就需要区这样的空间中去进行查找,找到个合适的空闲内存,分配过来.

结论:

进程在进行频繁创建的销毁的时候,开销比较大(开销主要体现在资源的申请和释放上)

线程:

线程也可以称为"轻量级进程",在进程的基础上,做出了改进

保持了独立调度执行,这样的"并发支持",同时省去了"分配资源""释放资源"带来的额外开销.

这个图上,是一个进程只有一个PCB,但实际上,一个进程可以有多个PCB,意味着一个线程包含了一个线程组,包含了多个线程,

操作系统,进行"多任务调度",本质上是在调度PCB~~(线程在系统中的调度规则,就和之前的线程是一样的)

多个线程的PCB的内存指针,指向的是同一个内存空间.

这就意味着,只是创建第一个线程的时候,需要从系统分配资源.后续的线程,就不必再分配,直接共用前面的那份资源就可以了.除了内存之外,文件描述符表(操作硬盘),这个东西也是多个进程共用一份的.

能够共享资源的这些线程,分成组,称为线程组,线程组也是线程的一部分.

线程组指向的内存空间包含了所有线程依赖的所有数据和代码,这些线程啃是各取所需,也可能是有一定公共的~~

数据也是共享的关系,意味着创建第一个线程之后,申请这些资源,后续的就不必去申请了,

线程解决的问题,是能够降低频繁申请释放带来的开销的.

程是自愿分配的基本单位,线程是调度执行的基本单位.

创建进程,资源就分配了,只不过,一个进程中至少包含一个线程~~(创建第一个线程的同时,进程也就被创建出来了).

加快效率:

多进程的解决方式:

创建新的进程,就需要申请更多的资源

多线程的解决方式:

引入更多的线程,速度变快,共享一份资源,资源开销更少了.

当引入的线程达到一定数量之后,再尝试引入新的进程之后,效率就很难再次提升了.

当线程数量过多的时候,线程之间会相互竞争,cpu的资源核心是有限的,非但不会提高效率,反而会增加调度的开销.

多线程之间可能会起冲突,就会导致代码中出现一些逻辑上的错误.(线程安全问题)

副作用:

多线程:一个线程如果抛出异常,并且没有处理好,就可能会导致整个进程被终止.

进程与线程的关系/区别

小结:

1.进程是包含线程的

2.每个线程,也是一个独立的执行流,可以执行一些代码,并且单独的参与到cpu的调度上(状态,上下文,优先级,记账信息.每个线程都有自己单独的一份)

3.每个进程都有自己的资源,进程中的线程共用这一份资源(文件描述符表和内存空间)

进程是资源分配的基本单位,线程是调度执行的基本单位.

4.进程和进程之间,不会相互影响,如果同一个进程中的线程,抛出异常,是可能会影响到其他线程的,会把整个进程中的所有线程都异常终止.

5.同一个进程中的线程之间,可能会相互干扰,引发线程问题/

6.线程也不是越多越好,要能够合适,如果线程太多了,调度开销可能就会非常明显.

线程创建

class MyTread extends Thread{
public void run()
{

}


}

这里我们创建出的线程,需要继承Thread.

这里的run方法,相当于卖你方法,一个java程序(进程)执行的入口方法,是一样的道理

一个进程至少有一个线程,这个进程中的第一个线程,称为主线程,main方法,就是主线程的入口方法.

此处的run方法,不需要程序员进行手动调用,会在合适的时机(线程创建好了之后),被jvm自动调用执行.

//MyThread t=new MyThread();
Thread t=new MyThread();
//这两个写法都可以
//调用thread的start方法,才会真正调用系统的api,在系统内核中创建出线程.
t.start();

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值