【多线程】初识多线程

news2024/9/24 1:20:47

1. 为什么要学习多线程?

首先相信各位小伙伴在学习 JavaSE 的时候,肯定写过一些小游戏吧,比如猜数字,关机小程序...但是如果现在要在猜数字小游戏上面加上一个功能,设定20秒没猜中,就判定游戏失败,那么请问,以没学过多线程的角度来看,你要如何增加这样的一个计时功能呢?即一遍玩游戏,一边计时。

上述只是方便各位理解多线程,本质多线程的意义就是能充分利用 CPU 的多核资源,解决并发编程的问题!

现在市面上买到笔记本所配的CPU,比如是八核十六线程,这里是指该 CPU 有八个物理核心,而每个物理核心上又虚拟了两个逻辑核心(超线程技术),对应的就是十六个线程,所以通过设备管理器会显示出十六个核心,一个线程对应一个核心(逻辑核心)。

所以上述说到的十六个线程指CPU最多可以同时有十六个线程处理任务!


2. 进程的认识

2.1 进程与线程的关系

相信大家都有打开过自己电脑的任务管理器,里面可以发现运行着各种软件,我们认为一个跑起来的程序,就是一个进程,进程与线程是包含的关系,一个进程中可以有多个线程!

其实也有很多软件是采用多进程实现并发编程的,比如谷歌浏览器,每打开一个页面就打开了一个进程,为什么可以采取多进程实现并发编程,但是还要使用多线程呢?

这里给各位小伙伴举个例子,相信大家就很容易理解了:

如果说,篮球哥火了,最近篮球的订单量特别大,一个工厂的生产线都已经忙不过来了,于是我的贴心助手给了我两套解决方案:

第一套方案:

这是第一种解决方案,就是让我再租个地,在建一个工厂,搞一套机器设备。

显然呀,这又要去租个新的地了,又要盖工厂,还得有一套新的物流体系,哎呀,这真的是又费钱又费力气呀,于是我摇摇头,这不行,换方案!其实上述这样的方案,就类似于多进程!

第二套方案:

这是第二种解决方案,再原有的工厂内部,再开辟一条生产流水线。

此时场地和物流体系,是不是就可以复用原来场子的呀,也不用再去租场地建厂子了,共用一个场子就好了!很明显第二种解决方案,成本上比第一种小很多!

根据上述的例子,就可以把篮球哥的工厂想象成进程,工厂里的生产流水线想象成线程!

总结:
一个进程最少包含一个线程,也可以包含多个线程,同一个进程里的多个线程之间,共用了同一份资源(主要是 内存 和 文件描述符表) 比如:在线程1 new 的对象,线程2,线程3都可以使用,在线程1打打开的文件,线程2,线程3都可以使用。

接着回答上面的问题,能使用多进程编程,为什么还要用线程?

其实上述举的例子也能清晰说明,创建一个进程开销是很大的!建工厂,搞生产线,弄一套物流...而创建线程只需要在原有的进程里开辟,比如只用在原来工厂多搞一套生产线即可。

销毁进程开销也很大呀!假如篮球哥不火了,订单变小了,只需要一个厂生产了,另一个厂就得销毁掉,还得拆物流,拆生产线,拆工厂,而如果是一个工厂有两套流水线,只需要拆其中一套流水线即可。

对于CPU来说,调度进程开销也比较大(后续讲解)

有了上述的情况线程就应运而生了,线程也叫做轻量级进程,这样的出现,在解决并发编程问题的前提下,让创建,销毁,调度的速度更快!

2.2 进程间如何通信?

针对进程使用的内存空间,进行了 "隔离",即引入了虚拟地址空间,代码里不在直接使用真实的物理地址了,而是使用虚拟的地址,由操作系统和专门的硬件负责进行虚拟地址到物理地址的转换。主要目的是为了防止进程1内存越界,影响到线程2的运行,这里我们简单了解,不深入讨论。

虽然有了进程隔离,但还是会引入新的问题,有些时候,不同的进程之间,需要进行数据的交互,这就涉及到进程之间如何通信呢?

其实是在隔离的基础上,开了个口子,搞一个多个进程都能访问到的 "公共空间",基于这个空间来进行交互数据即可,我们后续主要讲述:基于文件交互,基于网络交互。现在简单了解下即可。


3. 计算机如何描述进程的?

3.1 概述

进程是一个重要的软件资源,是由操作系统内核负责管理的。

使用了结构体(C语言的结构体)来描述了进程的属性,对于这个描述进程属性的结构体有一个名字,叫做 PCB(进程控制块),每个线程也对应一个 PCB!所以一个进程中可以有多个线程,也就是多个 PCB!

如何把这些PCB管理起来呢?用一个类似于双向链表的结构,把多个 PCB 给串到一起。

创建一个进程,本质就是创建一个 PCB,给插入到链表中
销毁一个进程,本质就是把链表上的 PCB 节点给删除掉
通过任务管理器看到的进程列表,本质就是遍历这个 PCB 链表

注意:一个进程里可以有多个线程,每个线程对应一个PCB,但是这些 PCB 并不是完全独立的,而是有共享的部分,比如一个进程里的多个 PCB 之间,pid是一样的(表示这个进程唯一标识),内存指针和文件描述符表也是一样的!

那么现在我们就要了解 PCB 包含了哪些描述进程的特征!

3.2 PCB 是如何描述进程的?

3.2.1 pid

pid 这个是进程里身份唯一的标识符,虽然一个进程里有多个线程,而这每个线程都对应一个 PCB 但是这些 PCB 的pid 都是一样的!用来标识这些线程是属于哪个进程的,也是这个进程的唯一标识符!

3.2.2 内存指针

内存指针,指向了该进程占用的内存是哪些,同理,虽然一个进程里包含多个线程,但是多个线程共享都是进程的资源,也就是利用了同一块内存,所以一个进程中线程对应PCB里内存指针,也是一样的!

3.3.3 文件描述符表

文件描述符表,表示打开的硬盘上的文件等其他资源,比如打开一个 .txt 文件,也就会对应在文件描述符表上新增一个表项(类似于数组的结构),后续学到的网络编程,也会被当成文件,也会在文件描述符表上申请表项,跟详细内容在文件 IO 章节讲解。

3.3.4 进程调度相关属性(下述属性每个线程都有自己的)

线程的状态:

就绪状态:随叫随到,线程随时准备去 CPU 上执行

运行状态:正在 CPU 上执行的,很多操作系统,不会明确区分就绪和运行状态

阻塞状态:短时间内无法到CPU上运行了(后续文章会详细讲解)

优先级:

先让哪个线程在 CPU 上运行,后让哪个线程在 CPU 上运行,这也是有一定的优先级的,操作系统进线程调度的时候并不是很公平的。

上下文:

操作系统在进行线程谢欢的时候,就需要把进程执行的"中间状态"记录下来,保存好,下次这个线程再到 CPU 上去运行的时候,就可以恢复上次的状态,继续往下执行,本质上可以理解为 "存档和读档",就是 CPU 中各个寄存器的值,保存上下文,就是把这些 CPU 寄存器的值记录保存到内存中(PCB),回复上下文,就是把内存中这些寄存器的值恢复回去。

记账信息:

操作系统,统计每个线程在 CPU 上占用的时间和执行的指令数目,根据这个来决定下一阶段如何调度。

3.3.5 总结

PCB 这里包含的属性是非常多的,不止我们上面所说的 pid,内存指针,文件描述符表,调度相关属性,还有其他内容,上述内容只是一些核心的属性,对于我们程序猿来说,了解以上属性已经是差不多了。

但是从调度相关属性开始,就有些小伙伴看不明白了,什么是调度?

4. 线程的调度

如何理解调度?从字面理解,你的领导将把你从北京公司调度到上海分公司去,而在 CPU 中,调度就是把一个线程拿到 CPU 核心上执行任务!

进程是 CPU 资源分配的最小单位,而线程是 CPU 调度的最小单位!

要了解线程的调度,首先要知道两个概念,并行和并发:

并行:简单来说,两个线程在 CPU 的两个核心上运行

并发:简单来说,两个线程在一个 CPU 核心上运行,对两个线程进行快速切换

并行好理解,并发可能就不太好理解了!

举个例子,张三喜欢打游戏,突然女朋友给打电话了,此时张三的脑子里就有两个信号,第一个处理游戏,第二个处理女朋友的电话,可是既不能放下游戏,也不能挂掉女朋友电话呀,于是张三就一边打游戏,一边接电话,只要张三脑子在游戏电话这两个任务中切换的够快,不错过游戏的内容,也不错过女朋友的电话内容,此时就能做到无缝衔接!

放在 CPU 中,先运行一下QQ音乐,再运行一下再运行下画图板,再运行一下QQ音乐,再运行画图板,只要切换的速度足够快(3.2GHz,每秒约运行32亿条指令),从我们的角度看是感知不到了,看起来好像是这几个线程再同时运行。

有了上面的理解,因此往往把并行和并发统称为并发,除非显式声明,否则后续我们说到的并发都是 并行+并发

问题来了,CPU 的核心数有限,如果一个核心上并发运行多个线程,虽然我们知道是进行快速的切换,但是他们是随机切换的!也就是 CPU 是随机调度的,线程是抢占式执行的!这一点后续内容会用代码给大家验证!此处大家了解即可。


5. 线程的缺点

前面我们谈到,一个进程中可以有多个线程,就如同我们上述举的工厂的例子有两条生产线,现在假设要生产 100 个篮球,一条生产线生产一个篮球需要花 2 个小时,那么 100 个篮球就需要花 200 个小时,如果是两条生产线,大概只需要花 100 个小时左右,那是不是生产线越多就越好呢?工厂能不能放下那么多生产线呢?

到这里问题来了,进程中的线程是不是也是越多越好呢?这里通过一个形象的例子来演示:

滑稽老铁今天过生日,喊了自己的一个好哥们一起吃蛋糕:

注意:上述情况房子就像进程,里面有多个线程,共享这个蛋糕的资源,两个人吃蛋糕可能绰绰有余,速度也不快不慢,但是我们往后看:

这时候另一个滑稽老铁说,就咱们俩个人啊,一点气氛都没有,蛋糕那么大,吃都吃不完!能不能多喊几个人来啊?这样才不会浪费蛋糕呀!而且要是能把俺暗恋的对象也喊来该多好!

于是滑稽老铁说,你想要气氛对吧,那俺就把咱的好兄弟都喊过来!

此时滑稽越多,是不是吃蛋糕的速度就越快呢?并不是,桌子旁边的位置是有限的,就好比 CPU 的核心数也是有限的,如果滑稽老铁太多了(线程),就会导致正在吃蛋糕的老铁没办法安心吃,一般一张桌子只能坐 12 个人,难不成一个人吃一口就换另一个人上来吃吗?这样的开销反而浪费在了 "换人吃蛋糕" 这个时间上,就好比如开销浪费在线程调度上了。

此时还有一个问题,一个滑稽老铁吃了一口下来了,空的这个座位有两个滑稽都想坐上去,可能就会打起来,谁也让着谁,会引发线程安全问题,也就是线程不安全!

更有一个特殊的情况,两个滑稽老铁争蛋糕上仅一份的巧克力,滑稽1把巧克力给抢走了!滑稽2抢不到巧克力就生气!拿起蛋糕往滑稽1脸上拍。

也就是如果一个线程抛异常处理的不好,很有可能把整个进程给带走了,其他老铁都吃不成蛋糕了,其他线程也就挂了!

总结:
线程模型,天然就是资源共享的,多个线程争抢同一个资源,容易有线程安全问题。
进程模型,天然是资源隔离的,很少有线程安全问题,进程之间通信,如果多个进程访问公共资源,才可能会出现线程安全问题。

本期只是简单带大家认识下多线程和进程,更多的是理论概念,后续博主则会根据代码实例,来进一步带大家走进多线程编程!


下期预告【多线程】Thread类

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

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

相关文章

数据结构:什么是堆,和二叉树有什么关系

堆栈模型 JS 代码执行时,值类型变量存储在栈,引用类型变量存储在堆。 // 变量 a 存储在栈里 let num1 1 let num2 num1 num2 2 // 这时打印 num1 是 1,num2 是 2。// { a: 1 } 存在堆里,obj1 只是一个指针引用 let obj1 { a…

华为 WATCH Ultimate 如何开通和使用北斗卫星卡

华为春季新品发布会发布了全新系列手表华为WATCH Ultimate非凡大师,实现了“向上捅破天”的突破性应用,让大家通过手表与世界一直相连。当用户在周围无信号(无蜂窝网络/WLAN网络覆盖)的情况下,处于空旷无遮挡的环境时&…

基于超声波传感器的液位测量及控制系统设计(STM32)

一、引言 随着工业的发展,计算机、微电子、传感器等高新技术的应用和研究,液位仪表的研制得到了长足的发展,以适应越来越高的应用要求。液位的测量在工业生产过程中已经起着相当重要的作用,其类型大概可以分为接触型和非接触型两大…

最近搭了一个数据监测看板。

在大数据时代(这个开头我已经看腻了 ),为了挖掘冗余数据的价值,数据分析需求日益增多,而分析结果的常见表现形式有数据分析报告和数据看板(大屏),与报告文档不同,数据看板…

8.1.0:DHTMLX Suite JavaScript UI Crack

适用于现代 Web 应用程序的强大 JavaScript 小部件库 - DHTMLX 套件 用于创建现代用户界面的轻量级、快速且通用的 JavaScript/HTML5 UI 小部件库。 DHTMLX Suite 有助于推进 Web 开发和构建具有丰富功能的数据密集型应用程序。 DHTMLX Suite 是一个 UI 小部件库,用…

移动端高性能Unity播放器实现方案

前情提要: 视听体验再进化——如何在24小时内全面升级你的视频应用 如何打造新时代的终端播放产品? 随着VR、AR、元宇宙等新玩法的出现,Unity平台的视频播放需求逐渐增加,比如下面两个动图就是在百度真实的案例。前者是演唱会场景…

ChatGPT能够知道当下最流行的开发语言,以及各语言哪个开发框架最火吗?

如果你准备成为一名开发人员,但是面对琳琅满目的开发语言,然后每种语言的开发框架却无从下手,张三推荐你学这个,李四推荐你学那个,而你的时间又是有限的,于是我决定问一问这个万事通ChatGPT。 目录 1. 目前…

C语言小项目 -- 扫雷游戏完整代码(递归展开 + 选择标记)

目录 🚀0. 游戏介绍: 🐷 游戏规则 🛸雷诀八条 🚀1. 开发环境及框架: 🚀2. 游戏具体功能分析实现: 🐷2.1 棋盘 🐷2.2 棋盘初始化 init_Board; &#x1…

用Abp实现两步验证(Two-Factor Authentication,2FA)登录(三):免登录验证

文章目录原理修改请求报文配置JwtBearerOptions生成Token校验Token修改认证EndPoint修改前端登录登出最终效果项目地址免登录验证是用户在首次两步验证通过后,在常用的设备(浏览器)中,在一定时间内不需要再次输入验证码直接登录。…

Go 语言 入门 基于 GoLand 2023.1 创建第一个Go程序

文章目录Go 语言 入门go 语言是什么?go 入门 需要 学习 什么?Go 语言有 那些优势?Go 语言 与 Java 语言 对比Go 语言 与Python 语言 对比Go 语言 基于 GoLand 创建第一个程序1. 打开 GoLand2.选择 new3. 选择SDK版本4. 输入项目名称,点击 cteate项目创建完成下一步,创建一个…

SpringBoot-心跳机制+redis实现网站实时在线人数统计

在社交网站中,通常需要实时统计某个网站的在线人数,通过该指标来实时帮助运营人员更好的维护网站业务: 先说一下目前在市面上主流的做法再加上我自己查阅的资料总结: 创建一个session监听器,在用户登录时即创建一个s…

WEB集群之反向代理,动静分离,NFS,mysql,MHA高可用

目录 第一章实验架构 1.1.实验图谱架构 1.2.实验前环境部署 第二章实验步骤 2.1.在ha01,ha02上部署keeplived,lvs-dr 2.2.Slave01,slave02安装nginx 2.3.LVS负载均衡 2.4.搭建动态网页 2.5.nginx反向代理 2.6.部署NFS 2.7.安装mysql 2.8.安装mha 2.9.主…

教你安装 CodeWhisperer: 一款个人免费的类似GitHubCopilot能代码补全的 AI 编程助手

1、官网 AI Code Generator - Amazon CodeWhisperer - AWS 官方扩展安装教程 2、安装VSCode 下载安装VSCode 3、VSCode安装CodeWhisperer插件 安装VSCode插件 - AWS Toolkit主侧栏,点击AWS ,展开CodeWhisperer,点击Start 在下拉菜单中点…

洗浴中心管理系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设!!! 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址: 更多系统资源库地址:骚戴的博客_CSDN_更多系统资源 更多系统…

煤矿井下人员精准定位系统,煤矿应急救援高效应用

煤矿行业的安全发展,事关数人民群众的生命财产安全。自2020年起,国家连续三年出台煤矿智能化建设及重大风险防控的相关指导政策,其中,2022年出台的《煤矿及重点非煤矿山重大灾害风险防控建设工作总体方案》中提到,要充…

52 openEuler搭建PostgreSQL数据库服务器-管理数据库角色

文章目录52 openEuler搭建PostgreSQL数据库服务器-管理数据库角色52.1 创建角色创建角色示例52.2 查看角色查看角色示例52.3 修改角色52.3.1 修改用户名52.3.2 修改用户示例52.3.3 修改用户密码52.3.4 修改角色密码示例52.4 删除角色删除角色示例52.5 角色授权角色授权示例52.6…

Python旅游好帮手:提前15天准备五一旅游景点详细数据

人生苦短,我用python 虽然还是有15天才放五一的假, 但是我的心早已经在旅游的路上了~ 本文源码:点击此处跳转文末名片获取 趁现在,先来用python做一个旅游攻略 知识点: requests parsel csv 第三方库&#x…

python查看时间序列数据的季节规律matplotlib画时间(10分钟为间隔)序列坐标

目录0 问题描述1. 案例12. 案例2参考资料0 问题描述 将多个时间序列数据,绘制到一张图上,每段时间序列数据一般只有几个月,少则 1 个月左右,想看它们的季节规律,需要去除年份,只看月份。 也就是横轴是1月…

44.CSS Grid布局概述

什么是CSS Grid? ● CSS Grid 是一组用于构建二维布局的 CSS 属性 ● CSS Grid 背后的主要思想是我们将容器元素划分为行和列,这些行和列可以填充是子元素。 ● 在两段式语境中,CSS网格允许我们写出更少的嵌套HTML和更容易阅读的CSS ● CSS …

二分查找原理及使用场景

建议使用左闭右开区间[l, r)查找。二分查找的最后,索引l,r会落到右区间第一个元素位置。因此但凡是能够见数组分成左右两个区间的都能应用二分查找法。 1、普通查值 常见问题方式:寻找含重复值的有序数组 [...,a, tar, tar, tar,.b....]&am…