多线程---认识线程

news2024/9/24 11:25:19

文章目录

  • 什么是进程?
    • 如何管理进程?
    • 认识PCB
    • 了解进程调度的过程
    • 虚拟地址空间
  • 什么是线程?
  • 进程 VS 线程
  • Thread类的属性和方法
    • Thread类的属性
    • Thread类的方法
      • 构造方法
      • 普通方法
  • 线程的状态

什么是进程?

进程,也叫做“任务”,一个跑起来的程序就是进程。也就是说进程是运行起来的程序。在同一时刻,操作系统中的进程有很多,他们是如何管理的呢?

如何管理进程?

管理进程实际上就是做两件事儿:

  1. 描述进程:详细的表示一个进程有哪些属性、哪些信息?这是通过一个结构体来实现的,这个结构体里面包含了进程的各种信息,这个结构体叫做PCB(进程控制块);
  2. 组织进程:通过一个数据结构把若干个PCB联系起来,使其可以进行增查改删。这个数据结构一般使用双向链表。

注:

  1. 创建进程实际上就是创建一个PCB,然后把它放到双向链表中。
  2. 结束进程实际上就是在双向链表中找到这个节点,然后把这个节点删除。
  3. 查看进程列表实际上是遍历整个双向链表。
  4. 一个进程可能是一个PCB,也可能是多个。

认识PCB

认识PCB,就是了解PCB里面到底包含了哪些信息:

  • pid:是一个进程的身份标识

    在同一台主机,同一时刻,这些进程的pid是唯一的。通过pid来区分进程。

  • 内存指针:描述进程持有的内存资源

    当我们双击一个可执行文件时,操作系统就要把这个文件的核心数据加载到内存中,同时会在内存中创建进程PCB。这就会给进程分配一定的内存空间,这个内存空间会被分为不同的区域,内存指针就是来描述每个区域是干嘛的。

  • 文件描述符表:描述进程持有的文件资源

    每个进程都可以打开一些文件(存储在硬盘上的数据),文件描述符表里就记录了当前这个进程打开了哪些文件。

  • 进程状态:描述进程当前能否被调用

    就绪状态:进程可以被调度到CPU上执行。
    阻塞状态:进程不能被调度到CPU上执行。

  • 进程优先级:描述进程调用的先后顺序

    在创建进程时,可以通过一些系统调用来干预优先级。

  • 进程上下文:保存当前进程执行过程中产生的中间结果。

    一个进程在CPU执行一会儿之后,会切换到另一个进程执行,在过一段时间之后可能会再次切换回来继续执行。那么此时就需要知道上次执行到哪儿了。进程上下文就是用来保存中间结果的。

  • 进程记账信息:统计一个进程在CPU上执行了多久

    进程在执行时由进程优先级控制执行哪个进程,但是这样就有可能导致某个进程一直执行不到。通过统计进程记账信息,能让进程调度更均衡,避免执行不到某个进程。

了解进程调度的过程

其中,进程状态、进程优先级、进程上下文和进程记账信息都是和进程调度相关的信息,那么什么是进程调度呢?

我们先要明白: 进程是操作系统进行资源分配的基本单位

进程调度其实是由“并行” + “并发”的方式执行的。

并行,即:在每个CPU核心上都可以独立的运行一个进程,多个CPU核心就可以同时运行多个进程。

并发,即:在一个CPU核心上,先运行一下进程1,再运行一下进程2,再运行一下进程3,再运行一下进程1…这样循环执行。只要切换的速度足够快,宏观上看起来三个进程就是在同时运行。

进程状态、进程优先级、进程上下文和进程记账信息存在的意义,就是支撑“进程调度”

虚拟地址空间

虚拟地址空间也是进程中非常关键的概念。

我们知道在创建进程时,都会给每个进程分配一定的内存空间,用来完成进程的工作。即:
在这里插入图片描述

在正常情况下,进程各自使用各自的内存,不会有任何问题。但是如果某个进程使用了野指针,不小心访问到了别的进程的内存且进行了修改。这就是个大问题:它这样做不仅仅影响到了自己的执行,而且还影响到了别人的执行。我们就通过虚拟地址空间来避免这个问题。

在这里插入图片描述

我们通过“虚拟地址空间”让每个进程都拥有自己的内存空间,并且和其他进程的内存空间隔离开。当进程要访问内存时通过MMU设备进行虚拟内存空间到真正内存空间的映射,访问真正的内存。如果发现有进程访问的内存越界,MMU设备就会进行拦截,关闭此进程,不让它影响到其他进程。

面对有些需要让多个进程配合的场景,又引入了进程间通信机制。它的原理就是:找到一块所有进程都能访问的公共资源,然后基于公共资源来交换数据。

什么是线程?

虽然多进程已经实现了并发编程,但是有一个巨大的问题:如果频繁的创建进程、销毁进程,那么这个操作就比较低效。

创建进程的过程:1. 创建PCB 2.给进程分配资源并赋值到PCB中 3. 把PCB插入链表
销毁进程的过程:1. 把PCB从链表上删除 2. 把PCB持有的资源释放 3. 销毁PCB

其中,分配资源和释放资源对操作系统来说要做的工作非常多,需要花费大量的时间。

因此,程序员就发明了“线程”。一个进程默认至少有一个线程,也可能有多个线程。这些线程都可以单独的在CPU上进行调度。最重要的是:同一个进程中的这些线程共用同一份系统资源(内存+文件),创建线程和销毁线程的开销远小于进程。所以,也把线程称为“轻量级进程”。

前面提到操作系统是通过PCB来描述进程的,更准确的说法是通过一组PCB来描述进程的。
每一个PCB对应一个线程,而一个进程可能包含多个线程。

使用多线程有一些优势:

  1. 能够充分利用多核CPU,提高效率。
  2. 只有创建第一个线程的时候需要申请资源,后续再创建新的线程都是共用同一份资源,节省了申请资源的开销;销毁线程的时候,也只有销毁到最后一个线程的时候才释放资源,节省了释放资源的开销。

使用多线程也有一些问题:

  1. 线程数目不是越多越好。当CPU核心已经饱和时,继续增加线程不会提高效率。反而会因为线程太多,线程的调度开销太大,影响了效率。
  2. 线程之间可能会相互影响到,造成线程安全问题
  3. 如果某个线程发生了意外就可能让整个进程奔溃

进程 VS 线程

  1. 进程包含线程
  2. 线程比进程更轻量,创建更快,销毁也更快
  3. 同一个进程的多个线程共用同一份系统资源(内存+文件),进程和进程之间则是有各自的系统资源(内存+文件)
  4. 进程是资源分配的基本单位,线程是调度执行的基本单位

Thread类的属性和方法

Thread类的属性

在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread();
        System.out.println(thread.getId());
        System.out.println(thread.getName());
        System.out.println(thread.getState());
        System.out.println(thread.getPriority());
        System.out.println(thread.isDaemon());
        System.out.println(thread.isAlive());
        System.out.println(thread.isInterrupted());

//        20
//        Thread-0
//        NEW
//        5
//        false
//        false
//        false

    }
}
  1. id是线程的唯一标识,不同的线程id不会重复。
  2. name在自己调试的时候会用到,可以自己在线程的构造方法里定义。
  3. state表示线程现在的状态(在下面介绍)
  4. priority在线程调度的时候会使用
  5. daemon:守护线程,也叫后台线程。前台进程:会阻止进程的退出,如果main线程执行完后,前台线程还没执行完,会等待前台线程执行完再退出进程;后台进程:不会组织进程的退出,当main线程执行完就退出进程。 我们创建的线程默认是前台线程。
  6. alive: 判断内核线程在不在。当new 出Thread对象但没有使用start方法启动时,不会把线程放入内核,使用start方法后才会把线程放入内核执行;当线程在内核执行完任务后,就会退出内核,清除内核线程,但是Thread对象还在。
  7. interrupt:线程中断,让线程提前结束,本质是让run方法尽快结束,不是让run方法执行到一半就退出。interrupt有两种情况:1. 如果线程正在执行 则设置标记位为true中断线程 2. 如果线程被阻塞 则唤醒sleep抛出异常 被catch捕获后在catch里处理,有两种中断的方式。
  • 使用线程库里面自带的标记位
    //通过使用标准库里自带的标记位
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // e.printStackTrace();

                    // [方式一] 立即结束线程
                    break;

                    // [方式二] 啥都不做, 不做理会. 线程继续执行

                    // [方式三] 线程稍后处理
                    // Thread.sleep(1000);
                    // break;
                }
            }
            System.out.println("t 线程执行完了");
        });

        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t.interrupt();
        System.out.println("设置让 t 线程结束!");
    }
  • 自定义一个标记位
//自己设置一个标记位  用来中断退出
    public static boolean isQuit = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!isQuit){
                System.out.println("执行线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();

        while (true){
            System.out.println("执行main");
            isQuit = true;
            System.out.println("手动中断线程");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

Thread类的方法

构造方法

在这里插入图片描述
构造方法主要是用来创建线程的,现在共有七种创建线程的方式,点击查看

在构造方法里可以添加一个String类型的参数,用来命名线程。

普通方法

  • start():启动线程。把线程放到内核中执行。

  • interrupt():中断线程。让线程提前退出。

  • join():线程等待。在main中调用join(),就是等待该线程执行完了再执行main线程。

  • sleep():线程休眠。让线程阻塞一段时间。

    PCB在管理线程时有俩个队列:一个就绪队列、一个阻塞队列。调用sleep()就是把线程放到阻塞队列里,等阻塞时间结束再放回就绪队列参与调度。

线程的状态

在这里插入图片描述

线程一共有六大状态,我们可以这样理解:
在这里插入图片描述

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

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

相关文章

ZooKeeper中节点的操作命令(查看、创建、删除节点)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

LLVM学习笔记(56)

4.1.4. DAG合并与合法化 来自SelectionDAGBuilder的SelectionDAG输出还不能进行指令选择,必须通过额外的转换——显示在上图。在指令选择前应用的遍序列如下: 匹配一组节点,在有利时使用更简单的构造来替换它们,DAG合并遍优化Se…

信息学奥赛一本通2061:【例1.2】梯形面积

2061:【例1.2】梯形面积 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 172550 通过数: 68183 【题目描述】 在梯形中阴影部分面积是150平方厘米,求梯形面积。 【输入】 (无) 【输出】 输出梯形面积(保留两位小数&a…

产品经理必看!提升效率的9款工具盘点,你都用过哪些?

产品经理是一款产品的灵魂人物,除了洞察用户需求和制定解决方案,每天还要腾出精力来协调各种资源,对接产品用户和内部多个部门,推动产品持续向前迭代。无论如何安排时间,大多数产品经理都没有足够的时间来处理他们的任…

本机spark 通idea连接Oracle的坑

1. 报错:Exception in thread "main" java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V 查询网上资料,是idea引入的scala运行环境版本与idea默认的scala版本不一样 也就是写的项目中的pom的spark版本与idea默认的版本不…

虚拟机安装openEuler系统

openEuler操作系统简介: openEuler是一款开源操作系统。当前openEuler内核源于Linux,支持鲲鹏及其他多种处理器,能够充分释放计算芯片的潜能,是由全球开源贡献者构建的高效、稳定、安全的开源操作系统,适用于数据库、大…

MySQL主从复制(基于binlog日志方式)

目录 一、什么是主从复制?二、主从复制原理、存在问题和解决方法2.1.主从复制原理2.2.主从复制存在的问题以及解决办法2.3.主从复制的同步模型2.4.拓展—Mysql并行复制 三、主从复制之基于binlog日志方式3.1.bin-log日志简介3.2.bin-log的使用3.2.1.开启binlog3.2.2…

软考系统架构师知识点集锦三:软件架构设计

一、考情分析 二、考点精讲 2.1软件架构的概念 2.1.1什么是架构(暂无定论) 架构设计就是需求分配,即将满足需求的职责分配到组件上。 软件架构风格是描述某-特定应用领域中系统组织方式的惯用模式。架构风格定义-个系统家族,即一个体系结构定义一个词汇表和一组约…

项目沟通管理案例题

1.规划沟通管理 没进行规划沟通管理 沟通管理计划不能一人制定 沟通管理计划内容不全 沟通管理计划完成后没有邀请有关干系人确认评审 制定沟通管理计划没有结合项目实际情况,只参考了以往的文件制定 项目经理对沟通管理经验不足 2.管理沟通 没做管理沟通 …

ps2024滤镜插件Portraiture

Photoshop 是最常用到的综合性的设计工具,虽然PS一直在迭代升级,但是在细节功能上,PS总是无法完全满足全部所有的用户需求,今天coco玛奇朵推荐一个个截至目前最受欢迎的免费的PS插件,有了这些功能扩展的插件后PS如虎添…

DC电源模块高功率元器件的散热问题

BOSHIDA DC电源模块高功率元器件的散热问题 随着电子产品的普及和发展,DC电源模块的应用越来越广泛,而高功率元器件的散热问题也变得日益重要。这是因为高功率元器件在工作时会消耗大量的电能,产生大量的热量,如果不能及时有效地…

第四章 文件管理 九、文件系统的层次结构

目录 一、层次结构图 二、例子 一、层次结构图 二、例子 用一个例子来辅助记忆文件系统的层次结构: 假设某用户请求删除文件“D:/工作目录/学生信息..xlsx”的最后100条记录。 1.用户需要通过操作系统提供的接口发出上述请求―一用户接口 2.由于用户提供的是文…

基于STM32室内空气净化监测系统设计

**单片机设计介绍,1649基于STM32室内空气净化监测系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序程序文档 六、 文章目录 一 概要 信息时代的进步,我们的生活潜移默化中发生了许多改变,物联网作为一个 陌生但…

4.1 数据库安全性概述

思维导图: 前言: - **第一章回顾**:数据库特点 - 统一的数据保护功能,确保数据安全、可靠、正确有效。 - 数据保护主要涵盖: 1. **数据的安全性**(本章焦点) 2. 数据的完整性(第…

『第七章』翩翩起舞的雨燕:顺序与并发执行

在本篇博文中,您将学到如下内容: 1. 顺序执行2. 主线程 Main Thread 的秘密3. 并发执行:GCD 与分发队列(DispatchQueue)4. 延时执行5. 数据竞争(Data Race)6. 线程间的同步7. 避免线程爆炸8. RunLoop 与定时器总结楚客自相送,沾裳春水边。 晚来风信好,并发上江船。 花映…

【Uva】11059-Maximum Product

1、题目 Uva 11059 2、题意 输入 n n n 个元素组成的序列 S S S,你需要找出一个乘积最大的连续子序列。如果这个最大的乘积不是正数,应输出0(表示无解)。 1 ≤ n ≤ 18 , − 10 ≤ S i ≤ 10 1 \le n \le 18&…

SpringBoot修复Spring AMQP反序列化漏洞(CVE-2023-34050)

问题描述: 2023年10月 Spring官方披露 CVE-2023-34050 Spring AMQP反序列化漏洞漏洞。由于 SimpleMessageConverter 或 SerializerMessageConverter 默认未配置白名单,导致可以反序列化任意类。新版本中在未配置白名单的情况下则不允许反序列化任意类。…

墨西哥专线相关问题快问快答

随着全球贸易的不断发展,越来越多的企业在寻求更便捷、高效的物流解决方案。墨西哥专线作为一种跨境物流方式,受到了越来越多企业的关注。本文将为您解答关于墨西哥专线的相关问题,帮助您更好地了解和运用这一物流方式。 一、墨西哥专线是什么…

为什么要拼命冲刺备考浙大MBA?这可能是最实在的理由了

离考试还有俩月不足,最后的时间里还可以做哪些事情?还有多少种可能?答案是不断往前走就有很多可能性,止步不前大概率是没有可能。无论是提前批面试中已经获得优秀资格的考生还是常规批的考生,最后的备考时间里要说动力…

NPM【问题 01】npm i node-sass@4.14.1报错not found: python2及Cannot download问题处理

node-sass安装问题处理 1.问题2.处理2.1 方案一【我的环境失败】2.2 方案二【成功】2.3 方案三【成功】 1.问题 gyp verb which failed Error: not found: python2 # 1.添加Python27的安装路径到环境变量 gyp verb check python checking for Python executable "python…