首先,在我们了解多线程之前,我们需要了解进程的概念以及进程和线程是什么关系?为什么我们Java中更多是需要利用多线程去解决一些问题,而不是多进程来解决?今天就让我们来解释一下。它们之间的关系。
什么是进程?
进程是操作系统对于正在运行的应用的一种抽象,也就是说,进程可以看作是程序的一次运行过程。同时,在操作系统中,进程又是操作系统进行资源分配的基本单位。
进程的属性
在操作系统中专门有一个结构体来描述进程的属性。
这个结构体统称为“进程控制块”PCB。在PCB中使用PCB,就可以去描述进程的属性。一个进程可以使用1个PCB和多个PCB来表示。系统中会使用双向链表这样的数据结构来组织多个PCB。
进程的身份标识
在进程中,它的身份标识是用pid来表示,每一个进程都会有一个pid,同一时刻,不同进程的pid也是不同的。说明每个pid也是独立的。
内存指针
在每个进程运行时,都会分配一定的内存空间。这个进程,内存空间,具体在哪里?以及分配的内存空间有哪些部分?这些部分都干了什么?
就需要用到内存指针来进行区分。
我们在C语言当中,每一次运行代码时,都会有一个黑框框来运行exe程序,而不是你打代码存储的cpp格式。这是因为exe当中包含了一些二进制指令,当运行exe程序,系统就会读取可执行文件的内容加载到内存中。
所以进程的内存空间,需要有专门的区域存储要执行的指令,以及指令依赖的数据,在此同时还要存储一些运行时产生的临时数据。
进程的分时复用和并发
一个进程如果要执行,就是需要cpu来执行上面的指令。
在早期的电脑中,都是单核cpu,一个cpu核心,同一时刻只能执行一个进程的指令。
故此我们把有需要的部分,分开,分时执行。
相当于一个cpu核心是一个舞台,一个进程表示一个演员,指令则为剧本。如果要演好一出戏,必须让演员在一幕戏结束后才能扮演另外的角色。
所以这叫做分时复用。
分时复用说明,如果这样的运行会消耗很大的环境,而且十分麻烦,效率十分低下。所以才会有了并发的说法。
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
只要这些演员的转速足够快,在人眼阶段无法识别出微毫的变化,就不会被发现,但是也可以看到在任何一个时刻点上只有一个程序在处理机上运行。况且,如果出现程序中异常,就会出现很严重的问题。
进程的状态
就绪状态:进程时刻准备好,去cpu上执行。(呼之即来挥之即去)
阻塞状态:某个进程,某种执行条件不具备,就导致这个进程暂时无法参与cpu的调度执行。
(比如:进程等待用户输入)
进程的总结
进程:跑起来的可执行程序
如何管理进程?
1.先描述:使用PCB结构表示出进程的各种属性。
2.后组织:使用双向链表,把这些PCB结构给串起来。
PCB当中有比较重要的属性:
1.pid(进程标识符)
2.内存指针(进程持有的内存资源)
3.文件描述符表(进程持有的硬盘资源)
4.状态
5.优先级
6.上下文
7.记账信息
在PCB的属性当中状态、优先级、上下文、记账信息都是用来完成“进程调度”的。他与进程持有的cpu资源,密切相关。而进程太多,CPU核心数目太少(狼多肉少),那么我们可以让这些进程轮番在cpu上执行。只要转速足够快,宏观中,就可以看起来这些进程在“同时”执行。这也叫做并发
上下文:它指的是在我们当中的CPU有一些寄存器,他只用来保存运算的中间结果的。没有特定含义。还有一部分寄存器有特定含义和特定作用。
1.保存当前执行到哪个指令(程序计数器:一个2字节/4字节/8字节整数,这个整数存的是一个内存地址)而内存地址就是程序下一条要执行的指令所在的位置。
2.维护栈相关的寄存器:通过这一组维护当前程序的调用栈。栈也是一块内存,这个内存就保存当前这个程序方法调用过程中,一系列的关系。(也包含局部变量和方法参数)ebp始终指向栈底,esp始终指向栈顶,修改esp的值就可以实现“入栈”或者“出栈”。
例如:在我们之前提到的exe里面就包含指令和数据。当运行exe时,操作系统就会把指令和数据加载到内存中(内存地址)
CPU就会先从内存中取到指令,然后再执行指令。初始情况下,程序计数器的值都会自动更新,默认情况下,直接指向下一条(顺序执行)
但是如果遇到 跳转类指令(jmp、jcmp、call)就会被设置成跳转到的地址。
记账信息:通过优先级机制,对不同的进程分配不同权重的资源。他会记录当前进程持有cpu的情况(在cpu执行多久了)就可以作为操作系统低调进程的参考依据。
这些就是进程的所有内容。
那什么是线程?
我们之前讨论说进程调度,前面的讨论都是基于“一个进程只有一个线程(PCB)的情况”。实际上,一个进程也可以多个线程,每个线程都可以独立进行调度。此外,每一个线程也有状态,优先级,上下文,记账信息。
一个进程,使用PCB表示,一个进程可能使用一个PCB表示,也可能使用多个PCB表示。每个PCB对应到一个线程上。不仅如此,此外,前面谈到的pid也是相同的,内存指针,文件描述符表,也是共用一份。
所以上述的结构,决定了线程的特点:
1.每个线程都可以独立的去cpu上调度执行。
2.同一个进程的多个线程之间,共用同一份内存空间和文件资源。
创建现成的时候,就不再需要重新申请资源,直接复用之前已经分配好的给进程的资源。省去了资源分配的开销,创建效率更高。
进程和线程的区别
1.进程包含线程,一个进程当中可以有一个线程,也可以有多个线程。
2.进程和线程中,都是为了实现并发编程场景,但线程不用重新申请资源,比进程更加轻化。
3.同一个进程的线程之间,共用同一份资源(内存+硬盘),省去了申请资源的开销。
在后续写代码的过程中,直接访问同个变量,就能完成“线程间通信”。
Java如何进行多线程编程?
线程是操作系统的概念,操作系统提供了一些API,可以操作线程。Java针对上述系统API进行了封装(跨平台)
那么我们直到在Java中存在一个Thread类,创建一个Thread对象,进一步就可以操作系统内部的线程了。然后使用这个类创建出一个线程就出来了。