【多线程】线程 与 进程

news2024/11/24 12:35:21

线程 与 进程

  • 一. 进程
    • 1. 操作系统
    • 2. 什么是进程/任务(Process/Task)
    • 3. 为什么要有进程
    • 3. 操作系统怎样管理进程
    • 4. 进程控制块抽象(PCB Process Control Block)
    • 5. 进程调度
    • 6. 内存分配 —— 内存管理(Memory Manage)
    • 7. 进程间通信(Inter Process Communication)
  • 二. 线程
    • 1. 线程是什么
    • 2. 为什么要有线程
    • 3. 进程和线程的区别与联系
    • 4. Java 的线程 和 操作系统线程 的关系
    • 5. 第一个多线程程序

一. 进程

1. 操作系统

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

操作系统的定位:
在这里插入图片描述
蓝色部分:系统调用、操作系统内核、驱动程序都属于操作系统。

操作系统由两个基本功能:

  1. 对下, 管理好各种设备。
  2. 对上, 给各种软件提供一个稳定的运行环境 。

2. 什么是进程/任务(Process/Task)

进程/任务: 就是跑起来的程序(运行起来的可执行文件),进程是操作系统对一个正在运行的程序的一种抽象,
换言之,可以把进程看做程序的一次运行过程。同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。

3. 为什么要有进程

因为操作系统支持多任务了,程序员也就需要并发编程了,通过进程,完全可以实现并发编程。

3. 操作系统怎样管理进程

  1. 先描述一个进程,明确一个进程上面的一些属性,此处的描述其实用的是 C 语言中的结构体(操作系统主要由 C/C++ 实现),这个结构体称为 PCB (Process Control Block) 进程控制块。
  2. 组织若干进程,使用一些数据结构把这些 PCB 放到一起。
    Linux 的典型实现就是使用 双向链表 把每个进程的 PCB 连接起来。

创建进程:先创建 PCB, 然后把 PCB 加到双向链表中。
销毁进程:找到链表上的 PCB,然后从链表中删除。
(我们平时查看任务管理器其实就是遍历这个链表。)

4. 进程控制块抽象(PCB Process Control Block)

计算机内部要管理任何现实事物,都需要将其抽象成一组有关联的、互为一体的数据。在 Java 语言中,我们可以通过类/对象来描述这一特征。

// 以下代码是 Java 代码的伪码形式
class PCB {
    // 进程的唯一标识 —— pid;
    // 进程关联的程序信息,例如哪个程序,加载到内存中的区域等
   // 分配给该资源使用的各个资源
    // 进度调度信息
}
  • PID:
    进程 ID -> 进程的身份证号。

  • 内存指针:
    指明这个进程要执行的代码/指令以及这个进程执行中所依赖的数据存放在内存的哪块区域。
    运行可执行文件时,操作系统会把这个 可执行文件(包含进程执行的二进制指令以及数据)加载到内存中变成进程。

  • 文件描述符表:
    程序运行过程中,经常要和文件打交道,进程每打开一个文件,就会在文件描述符表上添加一项。
    (这个表可视为一个数据,里面的每个元素又是一个结构体,对应一个文件信息。)
    一个进程只要启动,不管代码中是否包含打开/操作文件的代码,都会默认打开三个文件(系统自动打开)
    (1) 标准输入流
    (2) 标准输出流
    (3) 标准错误流

  • 状态:
    描述当前进程接下来应该怎样调度
    (1) 就绪状态:随时可以去 CPU 上执行
    (2) 阻塞状态:暂时不可去 CPU 上执行, 比如正在进行 IO 密集型操作,如读写数据。
    (3) 运行状态:正在 CPU 上执行

  • 优先级:
    根据进程的优先级来决定:先给哪个进程分配时间,后给哪个进程分配时间,以及给哪个进程分配的时间多, 给哪个进程分配的时间少。

  • 上下文:
    表示 该进程上次被调出 CPU 时,当时该进程的执行状态,下次该进程上 CPU 时,可恢复之前的状态,然后继续往下执行。
    进程被调度出 CPU 之前,需要把 CPU 寄存器里面的数据都保存到内存中(就是该 上下文字段),相当于存档了,下次 再被调上 CPU 执行时,就从刚才的内存中恢复这些数据到寄存器中,相当于时读档了,存档+读档存储的信息就被称为 上下文。

  • 记账信息:
    统计了每个进程都分别执行了多久,分别执行了哪些指令,分别排队等了多久,从而给进程调度提供知道依据。

以上只是几个核心属性。
这样,每一个 PCB 对象,就代表着一个实实在在运行着的程序,也就是进程。
操作系统再通过这种数据结构,例如线性表、搜索树等将 PCB 对象组织起来,方便管理时进行增删查改的操作。

5. 进程调度

就是 操作系统考虑 CPU 资源如何给各个进程分配。

6. 内存分配 —— 内存管理(Memory Manage)

操作系统对内存资源的分配,采用的是空间模式 —— 不同进程使用内存中的不同区域(虚拟地址空间),互相之间不会干扰。

虚拟地址空间: 程序中获取到的内存地址并不是真正的物理内存地址,而是经过一层抽象,虚拟出来的地址。

在这里插入图片描述

操作系统上同时运行多个进程,如果某个进程出现 bug 崩溃了,不会影响到其他进程(进程之间相互独立),就是因为内存按照虚拟地址空间分配。
一旦进程访问越界了,MMU 硬件设备就会向进程反馈,从而终止进程的非法操作。

7. 进程间通信(Inter Process Communication)

进程是操作系统进行资源分配的最小单位,这意味着各个进程互相之间是无法感受到对方存在的,这就是操作系统抽象出进程这一概念的初衷,这样便带来了进程之间互相具备 “隔离性(Isolation)”。
但现代的应用,要完成一个复杂的业务需求,往往无法通过一个进程独立完成,总是需要进程和进程进行配合地达到应用的目的,如此,进程之间就需要有进行“信息交换“的需求。进程间通信的需求就应运而生。
目前,主流操作系统提供的进程通信机制有如下:

  1. 管道
  2. 共享内存
  3. 文件
  4. 网络
  5. 信号量
  6. 信号

其中,网络是一种相对特殊的 IPC 机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的进程间进行通信。

二. 线程

1. 线程是什么

线程: 一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行着多份代码. 

比如如下场景:

一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴社保。
如果只有张三一个会计就会忙不过来,耗费的时间特别长。
为了让业务更快的办理好,张三又找来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队,自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。
此时,我们就把这种情况称为多线程,将一个大任务分解成不同小任务,交给不同执行流就分别排队执行。其中李四、王五都是张三叫来的,所以张三一般被称为主线程(Main Thread)。

2. 为什么要有线程

首先, “并发编程” 成为 “刚需”.

  • 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源.
  • 有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编程.

其次,用进程实现并发编程有点问题:

  • 频繁创建/销毁进程成本较高
  • 频繁的调度进程成本也是较高的

解决:

  1. 使用进程池
    进程池 虽然能解决上述问题, 提高效率,但是同时也有问题,进程池里面闲置的进程不使用的时候,也在占用并消耗系统资源,这样消耗的系统资源就太多了。
  2. 使用多线程
    线程比进程更加轻量,每个线程也可以执行一段代码(一个任务),也能并发编程,并且创建、销毁、调度线程的成本也比调度进程低很多。

为什么线程比进程更轻量?进程重在哪?

  • 进程重在资源的申请和释放,创建、销毁、调度进程就得重新分配 内存、硬盘、文件、网络等资源,对于资源的申请和释放本身就是比较低效的操作。
  • 而对于线程,线程包含在进程中,一个进程中的多个线程共用一份资源,只有创建第一个线程和释放最后一个线程时才涉及到资源的重新分配,中间线程的创建和销毁都不涉及到资源的重新分配。

多加一些线程,执行效率会不会进一步提高 ?

  • 一般来说会, 但是也不一定。
  • 因为多个线程共用一份资源(主要是指内存和文件描述符表,在线程 1 里面 new 的对象,在线程 2、3 里面也可以用,在线程 1 打开的文件在线程2、3 里面也可以直接使用),资源有限,如果线程太多,那么线程之间对资源的竞争会进一步加剧,如果时间全部浪费到竞争资源上面了,执行效率可能不升反降,整体的执行效率就被拖慢了。

最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 “线程池”(ThreadPool) 和 “协程” (Coroutine)

3. 进程和线程的区别与联系

  1. 进程是包含线程的. 每个进程至少有一个线程存在,即主线程。
    在这里插入图片描述

  2. 进程和线程都是为了解决并发编程这样的场景, 但是使用进程进行并发编程的话会有一些问题,频繁的创建、调度和销毁线程时效率低,相比之下,线程更轻量,创建、释放以及调度的效率高,只有创建第一个线程和释放最后一个线程时才需要资源的申请或释放。

  3. 进程是系统分配资源的最小单位,线程是系统 CPU 调度的最小单位。

  4. 进程之间具有独立性,每个进程有自己独立的虚拟地址空间,一个进程挂了,不会影响其他进程。一个进程中的多个线程共用同一块内存空间,一个线程挂了,可能影响其他线程,甚至导致整个进程崩溃。

4. Java 的线程 和 操作系统线程 的关系

线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库).
Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装.

5. 第一个多线程程序

  • 每个线程都是一个独立的执行流
  • 多个线程之间是 “并发” 执行的
class Main {

    private static class MyThread extends Thread {
        @Override
        public void run() {
            // 每个线程的任务都是循环 10 次
            for (int i = 1; i <= 10; i++) {
                // 打印当前线程的名字
                System.out.println(Thread.currentThread().getName() + "正在运行!");
                try {
                    // 休眠 1 s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();

        t1.start();
        t2.start();
        t3.start();
        // main 线程也循环 10 次
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

输出:
在这里插入图片描述

使用 JDK 中自带的 jconsole 工具就可以查看对应的线程:

在这里插入图片描述

注意:

  1. 一个进程可以同时占用多个 CPU 核心,因为线程才是 CPU 调度的基本单位。
  2. 并行:微观上同一时刻,多个核心同时运行。
  3. 并发:微观上,同一时刻,一个核心上只能运行一个进程, 但是它能够对进程进行足够快的切换,比如,一个 CPU 核心先运行 QQ,再运行一下 腾讯视频,再运行一下浏览器,只要切换的足够快,宏观上感知不到,人看起来就像这几个进程在同时运行。

好啦! 以上就是进程与线程的基本讲解,希望能帮到你 !
评论区欢迎指正 !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/988644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】匿名对象 | explicit | static静态成员 | 友元

匿名对象 有些情况下&#xff0c;我们创建变量只是临时用一用&#xff0c;以后不会再用到了。这时&#xff0c;如果创建变量还要起名字&#xff0c;是不是很多余&#xff1f; 对此&#xff0c;C引入了 匿名对象 供临时使用。 例如&#xff1a;如果我们创建对象slt&#xff0c…

什么是主动元数据管理?有何优势?

元数据是描述数据的数据&#xff0c;它提供数据的来源、含义、位置、所有权和创建等信息&#xff0c;主要用于跟踪、分类和分析。 元数据管理则是对元数据的创建、存储、整合、控制的一整套流程&#xff0c;是数据治理过程的一部分&#xff0c;能够支持基于元数据的相关需求和…

NFT Insider#106:The Sandbox 与 Light Matrix 以及鲁比尼拳击场达成战略合作

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

Android12之解析/proc/pid进程参数(一百六十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

python通过tkinter制作词云图工具

一、基本功能 1.采取上传文本文档&#xff08;仅支持.txt格式&#xff09;的方式统计词频 2.背景图形样式可选择已经设定好的&#xff0c;也可选择本地上传的&#xff08;支持.png .jpg .jpeg格式&#xff09; 3.本地上传的图片需要进行抠图处理&#xff0c;并将抠图结果保存…

大乘数法 -Java

题目链接&#xff1a;https://www.nowcoder.com/practice/c4c488d4d40d4c4e9824c3650f7d5571?tpId196&tqId37177&rp1&ru/exam/company&qru/exam/company&sourceUrl%2Fexam%2Fcompany&difficultyundefined&judgeStatusundefined&tags&titl…

SAP 批量删除变式

使用事务码se38进入变式&#xff0c;通过搜索帮助选中一个变式&#xff0c;点击显示。 点击目录&#xff0c;会显示所有的变式名称。 会显示当前程序的所有变式&#xff0c;然后点击删除按钮&#xff0c;选择需要删除的变式。

CVPR2023 RIFormer, 无需TokenMixer也能达成SOTA性能的极简ViT架构

编辑 | Happy 首发 | AIWalker 链接 | https://mp.weixin.qq.com/s/l3US8Dsd0yNC19o7B1ZBgw project, paper, code Token Mixer是ViT骨干非常重要的组成成分&#xff0c;它用于对不同空域位置信息进行自适应聚合&#xff0c;但常规的自注意力往往存在高计算复杂度与高延迟问题。…

FP130A 封装SOT23-5L 轨道电流测量IC

FP130A 封装SOT23-5L 轨道电流测量IC 一般说明 FP130A是一种宽共模范围高侧轨电流测量IC。它适用于电源系统&#xff0c;如电池充电器或开关电源的应用。它包括一个差分输入放大器和一个具有发射极输出的NPN晶体管。有三个外部电阻&#xff0c;轨道电流信号可以很容易地转换为I…

VR软件与管理后台的协议(微信扫码)

一、微信扫码登录 1、设计流程&#xff1a; ①、VR软件界面生成二维码&#xff0c;二维码中携带跳转小程序的链接及设备号、公司ID&#xff1b;用户通过扫码进入微信小程序点击界面一键启动&#xff0c;开始完善个人信息。 ②、用户点击一键启动&#xff0c;用户信息的授权状态…

入门人工智能 —— 学习 python 使用 IDE :vscode 完成编程 (2)

入门人工智能 —— 学习 python 使用 IDE &#xff1a;vscode 完成编程 &#xff08;2&#xff09; 安装和配置 VSCode创建和运行 Python 代码使用 VSCode 的调试功能 在上一篇文章中&#xff0c;介绍了如何入门人工智能编程&#xff0c;并开始了学习 Python 编程语言的基础知识…

润和软件HopeStage与上海瑞美云LIS系统管理软件完成产品兼容性互认证

近日&#xff0c;江苏润和软件股份有限公司&#xff08;以下简称“润和软件”&#xff09;HopeStage 操作系统与上海瑞美电脑科技有限公司&#xff08;以下简称“上海瑞美”&#xff09;瑞美云LIS系统管理软件完成产品兼容性测试。 测试结果表明&#xff0c;企业级通用操作系统…

NFTScan NFT API 在 NFTFi 开发中的应用

NFTFi 是“NFT”和“Finance”的缩写&#xff0c;旨在“增加 NFT 流动性&#xff0c;提供现金流”&#xff0c;NFTFi 是为 NFT 提供金融实用性的去中心化协议和应用程序的新兴生态系统&#xff0c;及使用 NFT 作为基础层在其上建设经济基础设施。 在实践中&#xff0c;NFTFi 协…

yolov7中Concat之后加注意力模块(最复杂的情况)

1、common.py中找到Concat模块&#xff0c;复制一份 2、要传参进来&#xff0c;dim通道数 3、然后找yolo.py模块&#xff0c;添加 4、yaml里替换 5、和加的位置也有关系

20 Spring Boot整合Redis

一、Redis简介 简单来说 Redis 就是一个使用 C 语言开发的数据库&#xff0c;不过与传统数据库不同的是 Redis 的数据是存在内存中的 &#xff0c;也就是它是内存数据库&#xff0c;所以读写速度非常快&#xff0c;因此 Redis 被广泛应用于缓存方向。 另外&#xff0c;Redis 除…

c++ vs2019 cpp20 规范,set源码分析

&#xff08;1&#xff09;set模板和map模板都是继承于一个父类 所以没有再详细注释。维持红黑树主要的功能都在父类_Tree里了&#xff0c;比如节点的添加&#xff0c;删除&#xff0c;查找。父类红黑树的操作&#xff0c;并不依赖于特定的数据类型。做到了父类模板的通用性。…

Linux学习之MySQL连接查询

接上一篇 连接查询 连接查询也中多表查询&#xff0c;常用于查询来自于多张表的数据&#xff0c;通过不同的连接方式把多张表组成一张新的临时表&#xff0c;再对临时表做数据处理。 #表基础信息&#xff0c;内容可从上一篇博客中查看 mysql> desc departments; ---------…

第15章_锁: (表级锁、页级锁、行锁、悲观锁、乐观锁、全局锁、死锁)

3.2 从数据操作的粒度划分&#xff1a;表级锁、页级锁、行锁 为了提高数据库并发度&#xff0c;每次锁定的数据范围越小越好&#xff0c;理论上每次只锁定当前操作的数据的方案会得到最大的并发度&#xff0c;但管理锁是很耗资源&#xff08;涉及获取、检查、释放锁等动作)。因…

我总结的《149个Python面试题.pdf》,都是干货!

大家好&#xff0c;我是涛哥。 很多小伙伴找Python面试资料&#xff0c;所以为了方便大家&#xff0c;涛哥我整理了《149个Python面试干货》&#xff0c;方便大家进行学习&#xff0c;尤其是要面试学习的同学可以重点学起来。 第一个部分就是讲Python基础相关内容 第二个部分…

JAVA毕业设计097—基于Java+Springboot+Vue+uniapp的医院挂号小程序系统(源码+数据库)

基于JavaSpringbootVueuniapp的医院挂号小程序系统(源码数据库)097 一、系统介绍 本系统前后端分离(网页端和小程序端都有) 本系统分为管理员、医院、用户三种角色(角色菜单可自行分配) 用户功能&#xff1a; 注册、登录、医院搜索、最新资讯、医生搜索、挂号预约、挂号记…